diff mbox series

[5/9] : C++ P0482R5 char8_t: Standard library support

Message ID f0837346-5771-80e1-886e-b584f7bfb6a4@honermann.net
State New
Headers show
Series : C++ P0482R5 char8_t implementation | expand

Commit Message

Tom Honermann Nov. 5, 2018, 7:40 p.m. UTC
This patch adds support to libstdc++ for the P0482R5 standard library 
changes.  This includes:
- New char8_t based specializations:
   - std::numeric_limits<char8_t>
   - std::char_traits<char8_t>
   - std::hash<u8string>
   - std::hash<pmr::u8string>
   - std::hash<u8string_view>
   - std::codecvt<char16_t, char8_t, std::mbstate_t>
   - std::codecvt<char32_t, char8_t, std::mbstate_t>
   - std::codecvt_byname<char16_t,char8_t,mbstate_t>
   - std::codecvt_byname<char32_t,char8_t,mbstate_t>
- New char8_t overloads:
   - u8string operator "" s(const char8_t* str, size_t len);
   - u8string_view operator""sv(const char8_t* str, size_t len);
- New type aliases:
   - std::u8string
   - std::u8string_view
   - std::atomic_char8_t
- Changed function signatures:
   - filesystem::path::u8string() returns u8string.
   - filesystem::path::generic_u8string() returns u8string.
- typeinfo for char8_t.
- New macros:
   - __cpp_lib_char8_t
   - ATOMIC_CHAR8_T_LOCK_FREE

For types and templates that existed in an experimental form prior to 
standardization, both the experimental and standardized variants have 
been updated.  The updates to the experimental versions are optional.

I'm not very familiar with how ABI versioning is done and I'm not 
confident that the changes in the .ver files are correct.  In 
particular, I'm unsure as to whether a CXXABI_3.0 section may be needed 
in gnu-versioned-namespace.ver and whether I'm correct in adding a new 
CXXABI_1.3.12 section in gnu.ver.  If I'm not mistaken, CXXABI has not 
already been bumped for gcc 9, so needs to be, but GLIBCXX has already 
been bumped and therefore does not need to be.

gcc/cp/ChangeLog:

2018-11-04  Tom Honermann  <tom@honermann.net>

      * name-lookup.c (get_std_name_hint): Added u8string as a name hint.

libstdc++-v3/ChangeLog:

2018-11-04  Tom Honermann  <tom@honermann.net>

      * config/abi/pre/gnu-versioned-namespace.ver (CXXABI_2.0): Add
      typeinfo symbols for char8_t.
      * config/abi/pre/gnu.ver: Add CXXABI_1.3.12.
      (GLIBCXX_3.4.26): Add symbols for specializations of
      numeric_limits and codecvt that involve char8_t.
      (CXXABI_1.3.12): Add typeinfo symbols for char8_t.
      * include/bits/atomic_base.h: Add atomic_char8_t.
      * include/bits/basic_string.h: Add std::hash<u8string> and
      operator""s(const char8_t*, size_t).
      * include/bits/c++config: Define _GLIBCXX_USE_CHAR8_T and
      __cpp_lib_char8_t.
      * include/bits/char_traits.h: Add char_traits<char8_t>.
      * include/bits/codecvt.h: Add
      codecvt<char16_t, char8_t, mbstate_t>,
      codecvt<char32_t, char8_t, mbstate_t>,
      codecvt_byname<char16_t, char8_t, mbstate_t>, and
      codecvt_byname<char32_t, char8_t, mbstate_t>.
      * include/bits/cpp_type_traits.h: Add __is_integer<char8_t> to
      recognize char8_t as an integral type.
      * include/bits/fs_path.h: (path::__is_encoded_char): Recognize
      char8_t.
      (path::u8string): Return std::u8string when char8_t support is
      enabled.
      (path::generic_u8string): Likewise.
      (path::_S_convert): Handle conversion from char8_t input.
      (path::_S_str_convert): Likewise.
      * include/bits/functional_hash.h: Add hash<char8_t>.
      * include/bits/locale_conv.h (__str_codecvt_out): Add overloads for
      char8_t.
      * include/bits/locale_facets.h (_GLIBCXX_NUM_UNICODE_FACETS): Bump
      for new char8_t specializations.
      * include/bits/localefwd.h: Add missing declarations of
      codecvt<char16_t, char, mbstate_t> and
      codecvt<char32_t, char, mbstate_t>.  Add char8_t declarations
      codecvt<char16_t, char8_t, mbstate_t> and
      codecvt<char32_t, char8_t, mbstate_t>.
      * include/bits/postypes.h: Add u8streampos
      * include/bits/stringfwd.h: Add declarations of
      char_traits<char8_t> and u8string.
      * include/c_global/cstddef: Add __byte_operand<char8_t>.
      * include/experimental/bits/fs_path.h (path::__is_encoded_char):
      Recognize char8_t.
      (path::u8string): Return std::u8string when char8_t support is
      enabled.
      (path::generic_u8string): Likewise.
      (path::_S_convert): Handle conversion from char8_t input.
      (path::_S_str_convert): Likewise.
      * include/experimental/string: Add u8string.
      * include/experimental/string_view: Add u8string_view,
      hash<experimental::u8string_view>, and
      operator""sv(const char8_t*, size_t).
      * include/std/atomic: Add atomic<char8_t> and atomic_char8_t.
      * include/std/charconv (__is_int_to_chars_type): Recognize char8_t
      as a character type.
      * include/std/limits: Add numeric_limits<char8_t>.
      * include/std/string_view: Add u8string_view,
      hash<experimental::u8string_view>, and
      operator""sv(const char8_t*, size_t).
      * include/std/type_traits: Add __is_integral_helper<char8_t>,
      __make_unsigned<char8_t>, and __make_signed<char8_t>.
      * libsupc++/atomic_lockfree_defines.h: Define
      ATOMIC_CHAR8_T_LOCK_FREE.
      * src/c++11/Makefile.am: Compile with -fchar8_t when compiling
      codecvt.cc and limits.cc so that char8_t specializations of
      numeric_limits and codecvt and emitted.
      * src/c++11/Makefile.in: Likewise.
      * src/c++11/codecvt.cc: Define members of
      codecvt<char16_t, char8_t, mbstate_t>,
      codecvt<char32_t, char8_t, mbstate_t>,
      codecvt_byname<char16_t, char8_t, mbstate_t>, and
      codecvt_byname<char32_t, char8_t, mbstate_t>.
      * src/c++11/limits.cc: Define members of
      numeric_limits<char8_t>.
      * src/c++98/Makefile.am: Compile with -fchar8_t when compiling
      locale_init.cc and localename.cc.
      * src/c++98/Makefile.in: Likewise.
      * src/c++98/locale_init.cc: Add initialization for the
      codecvt<char16_t, char8_t, mbstate_t> and
      codecvt<char32_t, char8_t, mbstate_t> facets.
      * src/c++98/localename.cc: Likewise.
      * testsuite/util/testsuite_abi.cc: Validate ABI bump.

Tom.

Comments

Tom Honermann Dec. 24, 2018, 2:27 a.m. UTC | #1
Attached is a revised patch that addresses changes in P0482R6.  Changes 
from the prior patch include:
- Updated the value of the __cpp_char8_t feature test macro to 201811.

Tested on x86_64-linux.

gcc/cp/ChangeLog:

2018-11-04  Tom Honermann  <tom@honermann.net>

      * name-lookup.c (get_std_name_hint): Added u8string as a name hint.

libstdc++-v3/ChangeLog:

2018-11-04  Tom Honermann  <tom@honermann.net>

      * config/abi/pre/gnu-versioned-namespace.ver (CXXABI_2.0): Add
      typeinfo symbols for char8_t.
      * config/abi/pre/gnu.ver: Add CXXABI_1.3.12.
      (GLIBCXX_3.4.26): Add symbols for specializations of
      numeric_limits and codecvt that involve char8_t.
      (CXXABI_1.3.12): Add typeinfo symbols for char8_t.
      * include/bits/atomic_base.h: Add atomic_char8_t.
      * include/bits/basic_string.h: Add std::hash<u8string> and
      operator""s(const char8_t*, size_t).
      * include/bits/c++config: Define _GLIBCXX_USE_CHAR8_T and
      __cpp_lib_char8_t.
      * include/bits/char_traits.h: Add char_traits<char8_t>.
      * include/bits/codecvt.h: Add
      codecvt<char16_t, char8_t, mbstate_t>,
      codecvt<char32_t, char8_t, mbstate_t>,
      codecvt_byname<char16_t, char8_t, mbstate_t>, and
      codecvt_byname<char32_t, char8_t, mbstate_t>.
      * include/bits/cpp_type_traits.h: Add __is_integer<char8_t> to
      recognize char8_t as an integral type.
      * include/bits/fs_path.h: (path::__is_encoded_char): Recognize
      char8_t.
      (path::u8string): Return std::u8string when char8_t support is
      enabled.
      (path::generic_u8string): Likewise.
      (path::_S_convert): Handle conversion from char8_t input.
      (path::_S_str_convert): Likewise.
      * include/bits/functional_hash.h: Add hash<char8_t>.
      * include/bits/locale_conv.h (__str_codecvt_out): Add overloads for
      char8_t.
      * include/bits/locale_facets.h (_GLIBCXX_NUM_UNICODE_FACETS): Bump
      for new char8_t specializations.
      * include/bits/localefwd.h: Add missing declarations of
      codecvt<char16_t, char, mbstate_t> and
      codecvt<char32_t, char, mbstate_t>.  Add char8_t declarations
      codecvt<char16_t, char8_t, mbstate_t> and
      codecvt<char32_t, char8_t, mbstate_t>.
      * include/bits/postypes.h: Add u8streampos
      * include/bits/stringfwd.h: Add declarations of
      char_traits<char8_t> and u8string.
      * include/c_global/cstddef: Add __byte_operand<char8_t>.
      * include/experimental/bits/fs_path.h (path::__is_encoded_char):
      Recognize char8_t.
      (path::u8string): Return std::u8string when char8_t support is
      enabled.
      (path::generic_u8string): Likewise.
      (path::_S_convert): Handle conversion from char8_t input.
      (path::_S_str_convert): Likewise.
      * include/experimental/string: Add u8string.
      * include/experimental/string_view: Add u8string_view,
      hash<experimental::u8string_view>, and
      operator""sv(const char8_t*, size_t).
      * include/std/atomic: Add atomic<char8_t> and atomic_char8_t.
      * include/std/charconv (__is_int_to_chars_type): Recognize char8_t
      as a character type.
      * include/std/limits: Add numeric_limits<char8_t>.
      * include/std/string_view: Add u8string_view,
      hash<experimental::u8string_view>, and
      operator""sv(const char8_t*, size_t).
      * include/std/type_traits: Add __is_integral_helper<char8_t>,
      __make_unsigned<char8_t>, and __make_signed<char8_t>.
      * libsupc++/atomic_lockfree_defines.h: Define
      ATOMIC_CHAR8_T_LOCK_FREE.
      * src/c++11/Makefile.am: Compile with -fchar8_t when compiling
      codecvt.cc and limits.cc so that char8_t specializations of
      numeric_limits and codecvt and emitted.
      * src/c++11/Makefile.in: Likewise.
      * src/c++11/codecvt.cc: Define members of
      codecvt<char16_t, char8_t, mbstate_t>,
      codecvt<char32_t, char8_t, mbstate_t>,
      codecvt_byname<char16_t, char8_t, mbstate_t>, and
      codecvt_byname<char32_t, char8_t, mbstate_t>.
      * src/c++11/limits.cc: Define members of
      numeric_limits<char8_t>.
      * src/c++98/Makefile.am: Compile with -fchar8_t when compiling
      locale_init.cc and localename.cc.
      * src/c++98/Makefile.in: Likewise.
      * src/c++98/locale_init.cc: Add initialization for the
      codecvt<char16_t, char8_t, mbstate_t> and
      codecvt<char32_t, char8_t, mbstate_t> facets.
      * src/c++98/localename.cc: Likewise.
      * testsuite/util/testsuite_abi.cc: Validate ABI bump.

Tom.
diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c
index 08632c382b7..5f2f8e865ca 100644
--- a/gcc/cp/name-lookup.c
+++ b/gcc/cp/name-lookup.c
@@ -5543,6 +5543,7 @@ get_std_name_hint (const char *name)
     {"basic_string", "<string>", cxx98},
     {"string", "<string>", cxx98},
     {"wstring", "<string>", cxx98},
+    {"u8string", "<string>", cxx2a},
     {"u16string", "<string>", cxx11},
     {"u32string", "<string>", cxx11},
     /* <string_view>.  */
diff --git a/libstdc++-v3/config/abi/pre/gnu-versioned-namespace.ver b/libstdc++-v3/config/abi/pre/gnu-versioned-namespace.ver
index c448b813331..b26cf1dc8ac 100644
--- a/libstdc++-v3/config/abi/pre/gnu-versioned-namespace.ver
+++ b/libstdc++-v3/config/abi/pre/gnu-versioned-namespace.ver
@@ -301,6 +301,11 @@ CXXABI_2.0 {
     _ZTSN10__cxxabiv120__si_class_type_infoE;
     _ZTSN10__cxxabiv121__vmi_class_type_infoE;
 
+    # typeinfo for char8_t
+    _ZTIDu;
+    _ZTIPDu;
+    _ZTIPKDu;
+
     # typeinfo for char16_t and char32_t
     _ZTIDs;
     _ZTIPDs;
diff --git a/libstdc++-v3/config/abi/pre/gnu.ver b/libstdc++-v3/config/abi/pre/gnu.ver
index e8cd286ef0c..b24ff3bf9ee 100644
--- a/libstdc++-v3/config/abi/pre/gnu.ver
+++ b/libstdc++-v3/config/abi/pre/gnu.ver
@@ -2055,6 +2055,18 @@ GLIBCXX_3.4.26 {
     _ZNSt13basic_filebufI[cw]St11char_traitsI[cw]EE4openEPKwSt13_Ios_Openmode;
 
     _ZN11__gnu_debug25_Safe_local_iterator_base16_M_attach_singleEPNS_19_Safe_sequence_baseEb;
+
+    # numeric_limits<char8_t>
+    _ZNSt14numeric_limitsIDuE[5-9]*;
+    _ZNSt14numeric_limitsIDuE1[0-7][hirt]*;
+    _ZNSt14numeric_limitsIDuE1[0-7]mi*;
+    _ZNSt14numeric_limitsIDuE1[0-7]max_e*;
+
+    # codecvt<char16_t, char8_t, mbstate_t>, codecvt<char32_t, char8_t, mbstate_t>
+    _ZNKSt7codecvtID[is]Du*;
+    _ZNSt7codecvtID[is]Du*;
+    _ZT[ISV]St7codecvtID[is]Du*E;
+
 } GLIBCXX_3.4.25;
 
 # Symbols in the support library (libsupc++) have their own tag.
@@ -2346,6 +2358,15 @@ CXXABI_1.3.11 {
 
 } CXXABI_1.3.10;
 
+CXXABI_1.3.12 {
+
+    # typeinfo for char8_t
+    _ZTIDu;
+    _ZTIPDu;
+    _ZTIPKDu;
+
+} CXXABI_1.3.11;
+
 # Symbols in the support library (libsupc++) supporting transactional memory.
 CXXABI_TM_1 {
 
diff --git a/libstdc++-v3/include/bits/atomic_base.h b/libstdc++-v3/include/bits/atomic_base.h
index 7a3354d9e6f..b3c8440491b 100644
--- a/libstdc++-v3/include/bits/atomic_base.h
+++ b/libstdc++-v3/include/bits/atomic_base.h
@@ -227,6 +227,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   // atomic_ulong    unsigned long
   // atomic_llong    long long
   // atomic_ullong   unsigned long long
+  // atomic_char8_t  char8_t
   // atomic_char16_t char16_t
   // atomic_char32_t char32_t
   // atomic_wchar_t  wchar_t
diff --git a/libstdc++-v3/include/bits/basic_string.h b/libstdc++-v3/include/bits/basic_string.h
index ae6530fcdc9..9a62ed2ddb7 100644
--- a/libstdc++-v3/include/bits/basic_string.h
+++ b/libstdc++-v3/include/bits/basic_string.h
@@ -6676,6 +6676,23 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #endif
 #endif /* _GLIBCXX_COMPATIBILITY_CXX0X */
 
+#ifdef _GLIBCXX_USE_CHAR8_T
+  /// std::hash specialization for u8string.
+  template<>
+    struct hash<u8string>
+    : public __hash_base<size_t, u8string>
+    {
+      size_t
+      operator()(const u8string& __s) const noexcept
+      { return std::_Hash_impl::hash(__s.data(),
+                                     __s.length() * sizeof(char8_t)); }
+    };
+
+  template<>
+    struct __is_fast_hash<hash<u8string>> : std::false_type
+    { };
+#endif
+
   /// std::hash specialization for u16string.
   template<>
     struct hash<u16string>
@@ -6728,6 +6745,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { return basic_string<wchar_t>{__str, __len}; }
 #endif
 
+#ifdef _GLIBCXX_USE_CHAR8_T
+    _GLIBCXX_DEFAULT_ABI_TAG
+    inline basic_string<char8_t>
+    operator""s(const char8_t* __str, size_t __len)
+    { return basic_string<char8_t>{__str, __len}; }
+#endif
+
     _GLIBCXX_DEFAULT_ABI_TAG
     inline basic_string<char16_t>
     operator""s(const char16_t* __str, size_t __len)
diff --git a/libstdc++-v3/include/bits/c++config b/libstdc++-v3/include/bits/c++config
index d499d32b51e..f2f52596af3 100644
--- a/libstdc++-v3/include/bits/c++config
+++ b/libstdc++-v3/include/bits/c++config
@@ -617,6 +617,17 @@ namespace std
 # endif
 #endif
 
+// Unless explicitly specified, enable char8_t extensions only if the core
+// language char8_t feature macro is defined.
+#ifndef _GLIBCXX_USE_CHAR8_T
+# ifdef __cpp_char8_t
+#  define _GLIBCXX_USE_CHAR8_T 1
+# endif
+#endif
+#ifdef _GLIBCXX_USE_CHAR8_T
+# define __cpp_lib_char8_t 201811
+#endif
+
 /* Define if __float128 is supported on this host. */
 #if defined(__FLOAT128__) || defined(__SIZEOF_FLOAT128__)
 #define _GLIBCXX_USE_FLOAT128
diff --git a/libstdc++-v3/include/bits/char_traits.h b/libstdc++-v3/include/bits/char_traits.h
index 63e810715f8..c5490ac37ec 100644
--- a/libstdc++-v3/include/bits/char_traits.h
+++ b/libstdc++-v3/include/bits/char_traits.h
@@ -492,6 +492,115 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   };
 #endif //_GLIBCXX_USE_WCHAR_T
 
+#ifdef _GLIBCXX_USE_CHAR8_T
+  template<>
+    struct char_traits<char8_t>
+    {
+      typedef char8_t           char_type;
+      typedef unsigned int      int_type;
+      typedef u8streampos       pos_type;
+      typedef streamoff         off_type;
+      typedef mbstate_t         state_type;
+
+      static _GLIBCXX17_CONSTEXPR void
+      assign(char_type& __c1, const char_type& __c2) _GLIBCXX_NOEXCEPT
+      { __c1 = __c2; }
+
+      static _GLIBCXX_CONSTEXPR bool
+      eq(const char_type& __c1, const char_type& __c2) _GLIBCXX_NOEXCEPT
+      { return __c1 == __c2; }
+
+      static _GLIBCXX_CONSTEXPR bool
+      lt(const char_type& __c1, const char_type& __c2) _GLIBCXX_NOEXCEPT
+      { return __c1 < __c2; }
+
+      static _GLIBCXX17_CONSTEXPR int
+      compare(const char_type* __s1, const char_type* __s2, size_t __n)
+      {
+#if __cplusplus > 201402
+	if (__builtin_constant_p(__n)
+	    && __constant_char_array_p(__s1, __n)
+	    && __constant_char_array_p(__s2, __n))
+	  return __gnu_cxx::char_traits<char_type>::compare(__s1, __s2, __n);
+#endif
+	if (__n == 0)
+	  return 0;
+	return __builtin_memcmp(__s1, __s2, __n);
+      }
+
+      static _GLIBCXX17_CONSTEXPR size_t
+      length(const char_type* __s)
+      {
+#if __cplusplus > 201402
+	if (__constant_string_p(__s))
+	  return __gnu_cxx::char_traits<char_type>::length(__s);
+#endif
+	size_t __i = 0;
+	while (!eq(__s[__i], char_type()))
+	  ++__i;
+	return __i;
+      }
+
+      static _GLIBCXX17_CONSTEXPR const char_type*
+      find(const char_type* __s, size_t __n, const char_type& __a)
+      {
+#if __cplusplus > 201402
+	if (__builtin_constant_p(__n)
+	    && __builtin_constant_p(__a)
+	    && __constant_char_array_p(__s, __n))
+	  return __gnu_cxx::char_traits<char_type>::find(__s, __n, __a);
+#endif
+	if (__n == 0)
+	  return 0;
+	return static_cast<const char_type*>(__builtin_memchr(__s, __a, __n));
+      }
+
+      static char_type*
+      move(char_type* __s1, const char_type* __s2, size_t __n)
+      {
+	if (__n == 0)
+	  return __s1;
+	return static_cast<char_type*>(__builtin_memmove(__s1, __s2, __n));
+      }
+
+      static char_type*
+      copy(char_type* __s1, const char_type* __s2, size_t __n)
+      {
+	if (__n == 0)
+	  return __s1;
+	return static_cast<char_type*>(__builtin_memcpy(__s1, __s2, __n));
+      }
+
+      static char_type*
+      assign(char_type* __s, size_t __n, char_type __a)
+      {
+	if (__n == 0)
+	  return __s;
+	return static_cast<char_type*>(__builtin_memset(__s, __a, __n));
+      }
+
+      static _GLIBCXX_CONSTEXPR char_type
+      to_char_type(const int_type& __c) _GLIBCXX_NOEXCEPT
+      { return char_type(__c); }
+
+      static _GLIBCXX_CONSTEXPR int_type
+      to_int_type(const char_type& __c) _GLIBCXX_NOEXCEPT
+      { return int_type(__c); }
+
+      static _GLIBCXX_CONSTEXPR bool
+      eq_int_type(const int_type& __c1, const int_type& __c2) _GLIBCXX_NOEXCEPT
+      { return __c1 == __c2; }
+
+      static _GLIBCXX_CONSTEXPR int_type
+      eof() _GLIBCXX_NOEXCEPT
+      { return static_cast<int_type>(-1); }
+
+      static _GLIBCXX_CONSTEXPR int_type
+      not_eof(const int_type& __c) _GLIBCXX_NOEXCEPT
+      { return eq_int_type(__c, eof()) ? 0 : __c; }
+    };
+#endif //_GLIBCXX_USE_CHAR8_T
+
 _GLIBCXX_END_NAMESPACE_VERSION
 } // namespace
 
diff --git a/libstdc++-v3/include/bits/codecvt.h b/libstdc++-v3/include/bits/codecvt.h
index bafa28c3a00..b99d54af2f9 100644
--- a/libstdc++-v3/include/bits/codecvt.h
+++ b/libstdc++-v3/include/bits/codecvt.h
@@ -573,6 +573,122 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       do_max_length() const throw();
     };
 
+#ifdef _GLIBCXX_USE_CHAR8_T
+  /** @brief  Class codecvt<char16_t, char8_t, mbstate_t> specialization.
+   *
+   *  Converts between UTF-16 and UTF-8.
+   */
+  template<>
+    class codecvt<char16_t, char8_t, mbstate_t>
+    : public __codecvt_abstract_base<char16_t, char8_t, mbstate_t>
+    {
+    public:
+      // Types:
+      typedef char16_t			intern_type;
+      typedef char8_t			extern_type;
+      typedef mbstate_t			state_type;
+
+    public:
+      static locale::id			id;
+
+      explicit
+      codecvt(size_t __refs = 0)
+      : __codecvt_abstract_base<char16_t, char8_t, mbstate_t>(__refs) { }
+
+    protected:
+      virtual
+      ~codecvt();
+
+      virtual result
+      do_out(state_type& __state, const intern_type* __from,
+	     const intern_type* __from_end, const intern_type*& __from_next,
+	     extern_type* __to, extern_type* __to_end,
+	     extern_type*& __to_next) const;
+
+      virtual result
+      do_unshift(state_type& __state,
+		 extern_type* __to, extern_type* __to_end,
+		 extern_type*& __to_next) const;
+
+      virtual result
+      do_in(state_type& __state,
+	     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;
+
+      virtual
+      int do_encoding() const throw();
+
+      virtual
+      bool do_always_noconv() const throw();
+
+      virtual
+      int do_length(state_type&, const extern_type* __from,
+		    const extern_type* __end, size_t __max) const;
+
+      virtual int
+      do_max_length() const throw();
+    };
+
+  /** @brief  Class codecvt<char32_t, char8_t, mbstate_t> specialization.
+   *
+   *  Converts between UTF-32 and UTF-8.
+   */
+  template<>
+    class codecvt<char32_t, char8_t, mbstate_t>
+    : public __codecvt_abstract_base<char32_t, char8_t, mbstate_t>
+    {
+    public:
+      // Types:
+      typedef char32_t			intern_type;
+      typedef char8_t			extern_type;
+      typedef mbstate_t			state_type;
+
+    public:
+      static locale::id			id;
+
+      explicit
+      codecvt(size_t __refs = 0)
+      : __codecvt_abstract_base<char32_t, char8_t, mbstate_t>(__refs) { }
+
+    protected:
+      virtual
+      ~codecvt();
+
+      virtual result
+      do_out(state_type& __state, const intern_type* __from,
+	     const intern_type* __from_end, const intern_type*& __from_next,
+	     extern_type* __to, extern_type* __to_end,
+	     extern_type*& __to_next) const;
+
+      virtual result
+      do_unshift(state_type& __state,
+		 extern_type* __to, extern_type* __to_end,
+		 extern_type*& __to_next) const;
+
+      virtual result
+      do_in(state_type& __state,
+	     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;
+
+      virtual
+      int do_encoding() const throw();
+
+      virtual
+      bool do_always_noconv() const throw();
+
+      virtual
+      int do_length(state_type&, const extern_type* __from,
+		    const extern_type* __end, size_t __max) const;
+
+      virtual int
+      do_max_length() const throw();
+    };
+#endif // _GLIBCXX_USE_CHAR8_T
+
 #endif // C++11
 
   /// class codecvt_byname [22.2.1.6].
@@ -639,6 +755,45 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       virtual
       ~codecvt_byname() { }
     };
+
+#if defined(_GLIBCXX_USE_CHAR8_T)
+  template<>
+    class codecvt_byname<char16_t, char8_t, mbstate_t>
+    : public codecvt<char16_t, char8_t, mbstate_t>
+    {
+    public:
+      explicit
+      codecvt_byname(const char* __s, size_t __refs = 0)
+      : codecvt<char16_t, char8_t, mbstate_t>(__refs) { }
+
+      explicit
+      codecvt_byname(const string& __s, size_t __refs = 0)
+      : codecvt_byname(__s.c_str(), __refs) { }
+
+    protected:
+      virtual
+      ~codecvt_byname() { }
+    };
+
+  template<>
+    class codecvt_byname<char32_t, char8_t, mbstate_t>
+    : public codecvt<char32_t, char8_t, mbstate_t>
+    {
+    public:
+      explicit
+      codecvt_byname(const char* __s, size_t __refs = 0)
+      : codecvt<char32_t, char8_t, mbstate_t>(__refs) { }
+
+      explicit
+      codecvt_byname(const string& __s, size_t __refs = 0)
+      : codecvt_byname(__s.c_str(), __refs) { }
+
+    protected:
+      virtual
+      ~codecvt_byname() { }
+    };
+#endif
+
 #endif // C++11
 
   // Inhibit implicit instantiations for required instantiations,
@@ -669,6 +824,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #if __cplusplus >= 201103L
   extern template class codecvt_byname<char16_t, char, mbstate_t>;
   extern template class codecvt_byname<char32_t, char, mbstate_t>;
+
+#if defined(_GLIBCXX_USE_CHAR8_T)
+  extern template class codecvt_byname<char16_t, char8_t, mbstate_t>;
+  extern template class codecvt_byname<char32_t, char8_t, mbstate_t>;
+#endif
+
 #endif
 
 #endif
diff --git a/libstdc++-v3/include/bits/cpp_type_traits.h b/libstdc++-v3/include/bits/cpp_type_traits.h
index 960d469f412..f4c655bb848 100644
--- a/libstdc++-v3/include/bits/cpp_type_traits.h
+++ b/libstdc++-v3/include/bits/cpp_type_traits.h
@@ -48,7 +48,7 @@
 // so function return values won't work:  We need compile-time entities.
 // We're left with types and constant  integral expressions.
 // Secondly, from the point of view of ease of use, type-based compile-time
-// information is -not- *that* convenient.  On has to write lots of
+// information is -not- *that* convenient.  One has to write lots of
 // overloaded functions and to hope that the compiler will select the right
 // one. As a net effect, the overall structure isn't very clear at first
 // glance.
@@ -171,6 +171,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     };
 # endif
 
+#ifdef _GLIBCXX_USE_CHAR8_T
+  template<>
+    struct __is_integer<char8_t>
+    {
+      enum { __value = 1 };
+      typedef __true_type __type;
+    };
+#endif
+
 #if __cplusplus >= 201103L
   template<>
     struct __is_integer<char16_t>
diff --git a/libstdc++-v3/include/bits/fs_path.h b/libstdc++-v3/include/bits/fs_path.h
index e3938d06d59..af6ac59a968 100644
--- a/libstdc++-v3/include/bits/fs_path.h
+++ b/libstdc++-v3/include/bits/fs_path.h
@@ -67,8 +67,13 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
   {
     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>>;
+	= __or_<is_same<_Ch, char>,
+#ifdef _GLIBCXX_USE_CHAR8_T
+		is_same<_Ch, char8_t>,
+#endif
+		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>>
@@ -301,7 +306,11 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
 #if _GLIBCXX_USE_WCHAR_T
     std::wstring   wstring() const;
 #endif
+#ifdef _GLIBCXX_USE_CHAR8_T
+    std::u8string  u8string() const;
+#else
     std::string    u8string() const;
+#endif // _GLIBCXX_USE_CHAR8_T
     std::u16string u16string() const;
     std::u32string u32string() const;
 
@@ -315,7 +324,11 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
 #if _GLIBCXX_USE_WCHAR_T
     std::wstring   generic_wstring() const;
 #endif
+#ifdef _GLIBCXX_USE_CHAR8_T
+    std::u8string  generic_u8string() const;
+#else
     std::string    generic_u8string() const;
+#endif // _GLIBCXX_USE_CHAR8_T
     std::u16string generic_u16string() const;
     std::u32string generic_u32string() const;
 
@@ -666,10 +679,22 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
       static string_type
       _S_convert(const _CharT* __f, const _CharT* __l)
       {
-	std::codecvt_utf8<_CharT> __cvt;
-	std::string __str;
-	if (__str_codecvt_out(__f, __l, __str, __cvt))
-	  return __str;
+#ifdef _GLIBCXX_USE_CHAR8_T
+	if constexpr (is_same_v<_CharT, char8_t>)
+	  {
+	    string_type __str(__f, __l);
+	    return __str;
+	  }
+	else
+	  {
+#endif
+	    std::codecvt_utf8<_CharT> __cvt;
+	    std::string __str;
+	    if (__str_codecvt_out(__f, __l, __str, __cvt))
+	      return __str;
+#ifdef _GLIBCXX_USE_CHAR8_T
+	  }
+#endif
 	_GLIBCXX_THROW_OR_ABORT(filesystem_error(
 	      "Cannot convert character sequence",
 	      std::make_error_code(errc::illegal_byte_sequence)));
@@ -850,6 +875,15 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
 	{
 	  if constexpr (is_same_v<_CharT, char>)
 	    return __u8str;
+#ifdef _GLIBCXX_USE_CHAR8_T
+	  else if constexpr (is_same_v<_CharT, char8_t>)
+	    {
+	      const char* __f = __u8str.data();
+	      const char* __l = __f + __u8str.size();
+	      _WString __wstr(__f, __l);
+	      return __wstr;
+	    }
+#endif
 	  else
 	    {
 	      _WString __wstr;
@@ -862,10 +896,22 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
 	    }
 	}
 #else
-      codecvt_utf8<_CharT> __cvt;
-      basic_string<_CharT, _Traits, _Allocator> __wstr{__a};
-      if (__str_codecvt_in(__first, __last, __wstr, __cvt))
-	return __wstr;
+#ifdef _GLIBCXX_USE_CHAR8_T
+      if constexpr (is_same_v<_CharT, char8_t>)
+	{
+	  basic_string<_CharT, _Traits, _Allocator> __wstr{__first, __last, __a};
+	  return __wstr;
+	}
+      else
+	{
+#endif
+	  codecvt_utf8<_CharT> __cvt;
+	  basic_string<_CharT, _Traits, _Allocator> __wstr{__a};
+	  if (__str_codecvt_in(__first, __last, __wstr, __cvt))
+	    return __wstr;
+#ifdef _GLIBCXX_USE_CHAR8_T
+	}
+#endif
 #endif
       _GLIBCXX_THROW_OR_ABORT(filesystem_error(
 	    "Cannot convert character sequence",
@@ -899,6 +945,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
   path::wstring() const { return string<wchar_t>(); }
 #endif
 
+#ifdef _GLIBCXX_USE_CHAR8_T
+  inline std::u8string
+  path::u8string() const { return string<char8_t>(); }
+#else
   inline std::string
   path::u8string() const
   {
@@ -917,6 +967,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
     return _M_pathname;
 #endif
   }
+#endif // _GLIBCXX_USE_CHAR8_T
 
   inline std::u16string
   path::u16string() const { return string<char16_t>(); }
@@ -966,9 +1017,15 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
   { return generic_string<wchar_t>(); }
 #endif
 
+#ifdef _GLIBCXX_USE_CHAR8_T
+  inline std::u8string
+  path::generic_u8string() const
+  { return generic_string<char8_t>(); }
+#else
   inline std::string
   path::generic_u8string() const
   { return generic_string(); }
+#endif
 
   inline std::u16string
   path::generic_u16string() const
diff --git a/libstdc++-v3/include/bits/functional_hash.h b/libstdc++-v3/include/bits/functional_hash.h
index 0f20b956b76..658b9606ea1 100644
--- a/libstdc++-v3/include/bits/functional_hash.h
+++ b/libstdc++-v3/include/bits/functional_hash.h
@@ -135,6 +135,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   /// Explicit specialization for wchar_t.
   _Cxx_hashtable_define_trivial_hash(wchar_t)
 
+#ifdef _GLIBCXX_USE_CHAR8_T
+  /// Explicit specialization for char8_t.
+  _Cxx_hashtable_define_trivial_hash(char8_t)
+#endif
+
   /// Explicit specialization for char16_t.
   _Cxx_hashtable_define_trivial_hash(char16_t)
 
diff --git a/libstdc++-v3/include/bits/locale_conv.h b/libstdc++-v3/include/bits/locale_conv.h
index e9b684b4f98..a09898a406f 100644
--- a/libstdc++-v3/include/bits/locale_conv.h
+++ b/libstdc++-v3/include/bits/locale_conv.h
@@ -158,6 +158,39 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       return __str_codecvt_out(__first, __last, __outstr, __cvt, __state, __n);
     }
 
+#ifdef _GLIBCXX_USE_CHAR8_T
+
+  // Convert wide character string to narrow.
+  template<typename _CharT, typename _Traits, typename _Alloc, typename _State>
+    inline bool
+    __str_codecvt_out(const _CharT* __first, const _CharT* __last,
+		      basic_string<char8_t, _Traits, _Alloc>& __outstr,
+		      const codecvt<_CharT, char8_t, _State>& __cvt,
+		      _State& __state, size_t& __count)
+    {
+      using _Codecvt = codecvt<_CharT, char8_t, _State>;
+      using _ConvFn
+	= codecvt_base::result
+	  (_Codecvt::*)(_State&, const _CharT*, const _CharT*, const _CharT*&,
+			char8_t*, char8_t*, char8_t*&) const;
+      _ConvFn __fn = &codecvt<_CharT, char8_t, _State>::out;
+      return __do_str_codecvt(__first, __last, __outstr, __cvt, __state,
+			      __count, __fn);
+    }
+
+  template<typename _CharT, typename _Traits, typename _Alloc, typename _State>
+    inline bool
+    __str_codecvt_out(const _CharT* __first, const _CharT* __last,
+		      basic_string<char8_t, _Traits, _Alloc>& __outstr,
+		      const codecvt<_CharT, char8_t, _State>& __cvt)
+    {
+      _State __state = {};
+      size_t __n;
+      return __str_codecvt_out(__first, __last, __outstr, __cvt, __state, __n);
+    }
+
+#endif  // _GLIBCXX_USE_CHAR8_T
+
 #ifdef _GLIBCXX_USE_WCHAR_T
 
 _GLIBCXX_BEGIN_NAMESPACE_CXX11
diff --git a/libstdc++-v3/include/bits/locale_facets.h b/libstdc++-v3/include/bits/locale_facets.h
index f6e0283fec9..a5f53a3defa 100644
--- a/libstdc++-v3/include/bits/locale_facets.h
+++ b/libstdc++-v3/include/bits/locale_facets.h
@@ -59,7 +59,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 # define  _GLIBCXX_NUM_FACETS 14
 # define  _GLIBCXX_NUM_CXX11_FACETS 8
 #endif
-#define _GLIBCXX_NUM_UNICODE_FACETS 2
+#ifdef _GLIBCXX_USE_CHAR8_T
+# define _GLIBCXX_NUM_UNICODE_FACETS 4
+#else
+# define _GLIBCXX_NUM_UNICODE_FACETS 2
+#endif
 
   // Convert string to numeric value of type _Tp and store results.
   // NB: This is specialized for all required types, there is no
diff --git a/libstdc++-v3/include/bits/localefwd.h b/libstdc++-v3/include/bits/localefwd.h
index e8690638c7a..e2a725f7ef0 100644
--- a/libstdc++-v3/include/bits/localefwd.h
+++ b/libstdc++-v3/include/bits/localefwd.h
@@ -139,6 +139,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<> class codecvt<char, char, mbstate_t>;
 #ifdef _GLIBCXX_USE_WCHAR_T
   template<> class codecvt<wchar_t, char, mbstate_t>;
+#endif
+#if __cplusplus >= 201103L
+  template<> class codecvt<char16_t, char, mbstate_t>;
+  template<> class codecvt<char32_t, char, mbstate_t>;
+#ifdef _GLIBCXX_USE_CHAR8_T
+  template<> class codecvt<char16_t, char8_t, mbstate_t>;
+  template<> class codecvt<char32_t, char8_t, mbstate_t>;
+#endif
 #endif
   template<typename _InternT, typename _ExternT, typename _StateT>
     class codecvt_byname;
diff --git a/libstdc++-v3/include/bits/postypes.h b/libstdc++-v3/include/bits/postypes.h
index 8abdbf02322..89ab9e8d548 100644
--- a/libstdc++-v3/include/bits/postypes.h
+++ b/libstdc++-v3/include/bits/postypes.h
@@ -235,6 +235,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   /// File position for wchar_t streams.
   typedef fpos<mbstate_t> wstreampos;
 
+#ifdef _GLIBCXX_USE_CHAR8_T
+  /// File position for char8_t streams.
+  typedef fpos<mbstate_t> u8streampos;
+#endif
+
 #if __cplusplus >= 201103L
   /// File position for char16_t streams.
   typedef fpos<mbstate_t> u16streampos;
diff --git a/libstdc++-v3/include/bits/stringfwd.h b/libstdc++-v3/include/bits/stringfwd.h
index 2b7f4612cbc..98f06f98d6b 100644
--- a/libstdc++-v3/include/bits/stringfwd.h
+++ b/libstdc++-v3/include/bits/stringfwd.h
@@ -58,6 +58,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<> struct char_traits<wchar_t>;
 #endif
 
+#ifdef _GLIBCXX_USE_CHAR8_T
+  template<> struct char_traits<char8_t>;
+#endif
+
 #if __cplusplus >= 201103L
   template<> struct char_traits<char16_t>;
   template<> struct char_traits<char32_t>;
@@ -79,6 +83,11 @@ _GLIBCXX_END_NAMESPACE_CXX11
   typedef basic_string<wchar_t> wstring;   
 #endif
 
+#ifdef _GLIBCXX_USE_CHAR8_T
+  /// A string of @c char8_t
+  typedef basic_string<char8_t> u8string;
+#endif
+
 #if __cplusplus >= 201103L
   /// A string of @c char16_t
   typedef basic_string<char16_t> u16string; 
diff --git a/libstdc++-v3/include/c_global/cstddef b/libstdc++-v3/include/c_global/cstddef
index b6d4a13c0b1..a6002236814 100644
--- a/libstdc++-v3/include/c_global/cstddef
+++ b/libstdc++-v3/include/c_global/cstddef
@@ -75,6 +75,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<> struct __byte_operand<unsigned char> { using __type = byte; };
 #ifdef _GLIBCXX_USE_WCHAR_T
   template<> struct __byte_operand<wchar_t> { using __type = byte; };
+#endif
+#ifdef _GLIBCXX_USE_CHAR8_T
+  template<> struct __byte_operand<char8_t> { using __type = byte; };
 #endif
   template<> struct __byte_operand<char16_t> { using __type = byte; };
   template<> struct __byte_operand<char32_t> { using __type = byte; };
diff --git a/libstdc++-v3/include/experimental/bits/fs_path.h b/libstdc++-v3/include/experimental/bits/fs_path.h
index 653b4a3fe85..ad346065e28 100644
--- a/libstdc++-v3/include/experimental/bits/fs_path.h
+++ b/libstdc++-v3/include/experimental/bits/fs_path.h
@@ -82,8 +82,13 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
     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>>;
+	= __or_<is_same<_Ch, char>,
+		is_same<_Ch, wchar_t>,
+#ifdef _GLIBCXX_USE_CHAR8_T
+		is_same<_Ch, char8_t>,
+#endif
+		is_same<_Ch, char16_t>,
+		is_same<_Ch, char32_t>>;
 
     template<typename _Iter,
 	     typename _Iter_traits = std::iterator_traits<_Iter>>
@@ -323,7 +328,11 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
 #if _GLIBCXX_USE_WCHAR_T
     std::wstring   wstring() const;
 #endif
+#ifdef _GLIBCXX_USE_CHAR8_T
+    std::u8string  u8string() const;
+#else
     std::string    u8string() const;
+#endif // _GLIBCXX_USE_CHAR8_T
     std::u16string u16string() const;
     std::u32string u32string() const;
 
@@ -337,7 +346,11 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
 #if _GLIBCXX_USE_WCHAR_T
     std::wstring   generic_wstring() const;
 #endif
+#ifdef _GLIBCXX_USE_CHAR8_T
+    std::u8string  generic_u8string() const;
+#else
     std::string    generic_u8string() const;
+#endif // _GLIBCXX_USE_CHAR8_T
     std::u16string generic_u16string() const;
     std::u32string generic_u32string() const;
 
@@ -672,10 +685,22 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
       static string_type
       _S_convert(const _CharT* __f, const _CharT* __l)
       {
-	std::codecvt_utf8<_CharT> __cvt;
-	std::string __str;
-	if (__str_codecvt_out(__f, __l, __str, __cvt))
-	  return __str;
+#ifdef _GLIBCXX_USE_CHAR8_T
+	if constexpr (is_same<_CharT, char8_t>::value)
+	  {
+	    string_type __str(__f, __l);
+	    return __str;
+	  }
+	else
+	  {
+#endif
+	    std::codecvt_utf8<_CharT> __cvt;
+	    std::string __str;
+	    if (__str_codecvt_out(__f, __l, __str, __cvt))
+	      return __str;
+#ifdef _GLIBCXX_USE_CHAR8_T
+	  }
+#endif
 	_GLIBCXX_THROW_OR_ABORT(filesystem_error(
 	      "Cannot convert character sequence",
 	      std::make_error_code(errc::illegal_byte_sequence)));
@@ -865,12 +890,24 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
 	    _WString*
 	    operator()(const _String& __from, _WString& __to, false_type)
 	    {
-	      // use codecvt_utf8<_CharT> to convert UTF-8 to wide string
-	      codecvt_utf8<_CharT> __cvt;
-	      const char* __f = __from.data();
-	      const char* __l = __f + __from.size();
-	      if (__str_codecvt_in(__f, __l, __to, __cvt))
-		return std::__addressof(__to);
+#ifdef _GLIBCXX_USE_CHAR8_T
+	      if constexpr (is_same<_CharT, char8_t>::value)
+	        {
+	          __to.assign(__from.begin(), __from.end());
+	          return std::__addressof(__to);
+	        }
+	      else
+	        {
+#endif
+	          // use codecvt_utf8<_CharT> to convert UTF-8 to wide string
+	          codecvt_utf8<_CharT> __cvt;
+	          const char* __f = __from.data();
+	          const char* __l = __f + __from.size();
+	          if (__str_codecvt_in(__f, __l, __to, __cvt))
+		    return std::__addressof(__to);
+#ifdef _GLIBCXX_USE_CHAR8_T
+	        }
+#endif
 	      return nullptr;
 	    }
 	  } __dispatch;
@@ -879,10 +916,22 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
 	    return *__p;
 	}
 #else
-      codecvt_utf8<_CharT> __cvt;
-      basic_string<_CharT, _Traits, _Allocator> __wstr{__a};
-      if (__str_codecvt_in(__first, __last, __wstr, __cvt))
-	return __wstr;
+#ifdef _GLIBCXX_USE_CHAR8_T
+      if constexpr (is_same<_CharT, char8_t>::value)
+        {
+          basic_string<_CharT, _Traits, _Allocator> __wstr{__first, __last, __a};
+          return __wstr;
+        }
+      else
+        {
+#endif
+          codecvt_utf8<_CharT> __cvt;
+          basic_string<_CharT, _Traits, _Allocator> __wstr{__a};
+          if (__str_codecvt_in(__first, __last, __wstr, __cvt))
+	    return __wstr;
+#ifdef _GLIBCXX_USE_CHAR8_T
+        }
+#endif
 #endif
       _GLIBCXX_THROW_OR_ABORT(filesystem_error(
 	    "Cannot convert character sequence",
@@ -897,6 +946,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
   path::wstring() const { return string<wchar_t>(); }
 #endif
 
+#ifdef _GLIBCXX_USE_CHAR8_T
+  inline std::u8string
+  path::u8string() const { return string<char8_t>(); }
+#else
   inline std::string
   path::u8string() const
   {
@@ -915,6 +968,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
     return _M_pathname;
 #endif
   }
+#endif // _GLIBCXX_USE_CHAR8_T
 
   inline std::u16string
   path::u16string() const { return string<char16_t>(); }
@@ -936,8 +990,13 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
   path::generic_wstring() const { return wstring(); }
 #endif
 
+#ifdef _GLIBCXX_USE_CHAR8_T
+  inline std::u8string
+  path::generic_u8string() const { return u8string(); }
+#else
   inline std::string
   path::generic_u8string() const { return u8string(); }
+#endif
 
   inline std::u16string
   path::generic_u16string() const { return u16string(); }
diff --git a/libstdc++-v3/include/experimental/string b/libstdc++-v3/include/experimental/string
index 5a96bf78d73..d1ee5d369b3 100644
--- a/libstdc++-v3/include/experimental/string
+++ b/libstdc++-v3/include/experimental/string
@@ -73,6 +73,9 @@ inline namespace fundamentals_v2
     // basic_string typedef names using polymorphic allocator in namespace
     // std::experimental::pmr
     typedef basic_string<char> string;
+#ifdef _GLIBCXX_USE_CHAR8_T
+    typedef basic_string<char8_t> u8string;
+#endif
     typedef basic_string<char16_t> u16string;
     typedef basic_string<char32_t> u32string;
     typedef basic_string<wchar_t> wstring;
diff --git a/libstdc++-v3/include/experimental/string_view b/libstdc++-v3/include/experimental/string_view
index b3bc1a9fb4f..0cbdb663cca 100644
--- a/libstdc++-v3/include/experimental/string_view
+++ b/libstdc++-v3/include/experimental/string_view
@@ -565,6 +565,9 @@ inline namespace fundamentals_v1
   using string_view = basic_string_view<char>;
 #ifdef _GLIBCXX_USE_WCHAR_T
   using wstring_view = basic_string_view<wchar_t>;
+#endif
+#ifdef _GLIBCXX_USE_CHAR8_T
+  using u8string_view = basic_string_view<char8_t>;
 #endif
   using u16string_view = basic_string_view<char16_t>;
   using u32string_view = basic_string_view<char32_t>;
@@ -605,6 +608,21 @@ inline namespace fundamentals_v1
     { };
 #endif
 
+#ifdef _GLIBCXX_USE_CHAR8_T
+  template<>
+    struct hash<experimental::u8string_view>
+    : public __hash_base<size_t, experimental::u8string_view>
+    {
+      size_t
+      operator()(const experimental::u8string_view& __s) const noexcept
+      { return std::_Hash_impl::hash(__s.data(), __s.length()); }
+    };
+
+  template<>
+    struct __is_fast_hash<hash<experimental::u8string_view>> : std::false_type
+    { };
+#endif
+
   template<>
     struct hash<experimental::u16string_view>
     : public __hash_base<size_t, experimental::u16string_view>
@@ -652,6 +670,12 @@ namespace experimental
     { return basic_string_view<wchar_t>{__str, __len}; }
 #endif
 
+#ifdef _GLIBCXX_USE_CHAR8_T
+    inline constexpr basic_string_view<char8_t>
+    operator""sv(const char8_t* __str, size_t __len) noexcept
+    { return basic_string_view<char8_t>{__str, __len}; }
+#endif
+
     inline constexpr basic_string_view<char16_t>
     operator""sv(const char16_t* __str, size_t __len) noexcept
     { return basic_string_view<char16_t>{__str, __len}; }
diff --git a/libstdc++-v3/include/std/atomic b/libstdc++-v3/include/std/atomic
index 002604676cd..fe0c141fe1f 100644
--- a/libstdc++-v3/include/std/atomic
+++ b/libstdc++-v3/include/std/atomic
@@ -904,6 +904,31 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #endif
     };
 
+#ifdef _GLIBCXX_USE_CHAR8_T
+  /// Explicit specialization for char8_t.
+  template<>
+    struct atomic<char8_t> : __atomic_base<char8_t>
+    {
+      typedef char8_t 			__integral_type;
+      typedef __atomic_base<char8_t> 	__base_type;
+
+      atomic() noexcept = default;
+      ~atomic() noexcept = default;
+      atomic(const atomic&) = delete;
+      atomic& operator=(const atomic&) = delete;
+      atomic& operator=(const atomic&) volatile = delete;
+
+      constexpr atomic(__integral_type __i) noexcept : __base_type(__i) { }
+
+      using __base_type::operator __integral_type;
+      using __base_type::operator=;
+
+#if __cplusplus > 201402L
+    static constexpr bool is_always_lock_free = ATOMIC_CHAR8_T_LOCK_FREE == 2;
+#endif
+    };
+#endif
+
   /// Explicit specialization for char16_t.
   template<>
     struct atomic<char16_t> : __atomic_base<char16_t>
@@ -990,6 +1015,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   /// atomic_wchar_t
   typedef atomic<wchar_t>		atomic_wchar_t;
 
+#ifdef _GLIBCXX_USE_CHAR8_T
+  /// atomic_char8_t
+  typedef atomic<char8_t>		atomic_char8_t;
+#endif
+
   /// atomic_char16_t
   typedef atomic<char16_t>		atomic_char16_t;
 
diff --git a/libstdc++-v3/include/std/charconv b/libstdc++-v3/include/std/charconv
index 922c2c7e25e..852e8b2b696 100644
--- a/libstdc++-v3/include/std/charconv
+++ b/libstdc++-v3/include/std/charconv
@@ -66,6 +66,9 @@ namespace __detail
 	  __not_<__is_one_of<_Tp, bool, char16_t, char32_t
 #if _GLIBCXX_USE_WCHAR_T
 	  , wchar_t
+#endif
+#if _GLIBCXX_USE_CHAR8_T
+	  , char8_t
 #endif
 	    >>>;
 
diff --git a/libstdc++-v3/include/std/limits b/libstdc++-v3/include/std/limits
index e8eb6a1e0c4..0bf635e7b92 100644
--- a/libstdc++-v3/include/std/limits
+++ b/libstdc++-v3/include/std/limits
@@ -374,6 +374,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   // Now there follow 16 explicit specializations.  Yes, 16.  Make sure
   // you get the count right. (18 in C++11 mode, with char16_t and char32_t.)
+  // (+1 if char8_t is enabled.)
 
   // _GLIBCXX_RESOLVE_LIB_DEFECTS
   // 184. numeric_limits<bool> wording problems
@@ -725,6 +726,69 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        = round_toward_zero;
     };
 
+#if _GLIBCXX_USE_CHAR8_T
+  /// numeric_limits<char8_t> specialization.
+  template<>
+    struct numeric_limits<char8_t>
+    {
+      static constexpr bool is_specialized = true;
+
+      static constexpr char8_t
+      min() noexcept { return __glibcxx_min (char8_t); }
+
+      static constexpr char8_t
+      max() noexcept { return __glibcxx_max (char8_t); }
+
+      static constexpr char8_t
+      lowest() noexcept { return min(); }
+
+      static constexpr int digits = __glibcxx_digits (char8_t);
+      static constexpr int digits10 = __glibcxx_digits10 (char8_t);
+      static constexpr int max_digits10 = 0;
+      static constexpr bool is_signed = __glibcxx_signed (char8_t);
+      static constexpr bool is_integer = true;
+      static constexpr bool is_exact = true;
+      static constexpr int radix = 2;
+
+      static constexpr char8_t
+      epsilon() noexcept { return 0; }
+
+      static constexpr char8_t
+      round_error() noexcept { return 0; }
+
+      static constexpr int min_exponent = 0;
+      static constexpr int min_exponent10 = 0;
+      static constexpr int max_exponent = 0;
+      static constexpr int max_exponent10 = 0;
+
+      static constexpr bool has_infinity = false;
+      static constexpr bool has_quiet_NaN = false;
+      static constexpr bool has_signaling_NaN = false;
+      static constexpr float_denorm_style has_denorm = denorm_absent;
+      static constexpr bool has_denorm_loss = false;
+
+      static constexpr char8_t
+      infinity() noexcept { return char8_t(); }
+
+      static constexpr char8_t
+      quiet_NaN() noexcept { return char8_t(); }
+
+      static constexpr char8_t
+      signaling_NaN() noexcept { return char8_t(); }
+
+      static constexpr char8_t
+      denorm_min() noexcept { return char8_t(); }
+
+      static constexpr bool is_iec559 = false;
+      static constexpr bool is_bounded = true;
+      static constexpr bool is_modulo = !is_signed;
+
+      static constexpr bool traps = __glibcxx_integral_traps;
+      static constexpr bool tinyness_before = false;
+      static constexpr float_round_style round_style = round_toward_zero;
+    };
+#endif
+
 #if __cplusplus >= 201103L
   /// numeric_limits<char16_t> specialization.
   template<>
diff --git a/libstdc++-v3/include/std/string b/libstdc++-v3/include/std/string
index dd60df2ba6e..7fd29cc163a 100644
--- a/libstdc++-v3/include/std/string
+++ b/libstdc++-v3/include/std/string
@@ -62,6 +62,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       using basic_string = std::basic_string<_CharT, _Traits,
 					     polymorphic_allocator<_CharT>>;
     using string    = basic_string<char>;
+#ifdef _GLIBCXX_USE_CHAR8_T
+    using u8string  = basic_string<char8_t>;
+#endif
     using u16string = basic_string<char16_t>;
     using u32string = basic_string<char32_t>;
 #ifdef _GLIBCXX_USE_WCHAR_T
diff --git a/libstdc++-v3/include/std/string_view b/libstdc++-v3/include/std/string_view
index 9e0f6a723e4..b7ee0a586f5 100644
--- a/libstdc++-v3/include/std/string_view
+++ b/libstdc++-v3/include/std/string_view
@@ -555,7 +555,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #ifdef _GLIBCXX_USE_WCHAR_T
   using wstring_view = basic_string_view<wchar_t>;
 #endif
-
+#ifdef _GLIBCXX_USE_CHAR8_T
+  using u8string_view = basic_string_view<char8_t>;
+#endif
   using u16string_view = basic_string_view<char16_t>;
   using u32string_view = basic_string_view<char32_t>;
 
@@ -593,6 +595,21 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { };
 #endif
 
+#ifdef _GLIBCXX_USE_CHAR8_T
+  template<>
+    struct hash<u8string_view>
+    : public __hash_base<size_t, u8string_view>
+    {
+      size_t
+      operator()(const u8string_view& __str) const noexcept
+      { return std::_Hash_impl::hash(__str.data(), __str.length()); }
+    };
+
+  template<>
+    struct __is_fast_hash<hash<u8string_view>> : std::false_type
+    { };
+#endif
+
   template<>
     struct hash<u16string_view>
     : public __hash_base<size_t, u16string_view>
@@ -637,6 +654,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { return basic_string_view<wchar_t>{__str, __len}; }
 #endif
 
+#ifdef _GLIBCXX_USE_CHAR8_T
+    inline constexpr basic_string_view<char8_t>
+    operator""sv(const char8_t* __str, size_t __len) noexcept
+    { return basic_string_view<char8_t>{__str, __len}; }
+#endif
+
     inline constexpr basic_string_view<char16_t>
     operator""sv(const char16_t* __str, size_t __len) noexcept
     { return basic_string_view<char16_t>{__str, __len}; }
diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 86b58ccf225..5a1c2c0e08a 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -234,6 +234,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     : public true_type { };
 #endif
 
+#ifdef _GLIBCXX_USE_CHAR8_T
+  template<>
+    struct __is_integral_helper<char8_t>
+    : public true_type { };
+#endif
+
   template<>
     struct __is_integral_helper<char16_t>
     : public true_type { };
@@ -1673,8 +1679,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	= typename __match_cv_qualifiers<_Tp, __unsigned_type>::__type;
     };
 
-  // wchar_t, char16_t and char32_t are integral types but are neither
-  // signed integer types nor unsigned integer types, so must be
+  // wchar_t, char8_t, char16_t and char32_t are integral types but are
+  // neither signed integer types nor unsigned integer types, so must be
   // transformed to the unsigned integer type with the smallest rank.
   // Use the partial specialization for enumeration types to do that.
 #if defined(_GLIBCXX_USE_WCHAR_T)
@@ -1686,6 +1692,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     };
 #endif
 
+#ifdef _GLIBCXX_USE_CHAR8_T
+  template<>
+    struct __make_unsigned<char8_t>
+    {
+      using __type
+	= typename __make_unsigned_selector<char8_t, false, true>::__type;
+    };
+#endif
+
   template<>
     struct __make_unsigned<char16_t>
     {
@@ -1803,6 +1818,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     };
 #endif
 
+#if defined(_GLIBCXX_USE_CHAR8_T)
+  template<>
+    struct __make_signed<char8_t>
+    {
+      using __type
+	= typename __make_signed_selector<char8_t, false, true>::__type;
+    };
+#endif
+
   template<>
     struct __make_signed<char16_t>
     {
diff --git a/libstdc++-v3/libsupc++/atomic_lockfree_defines.h b/libstdc++-v3/libsupc++/atomic_lockfree_defines.h
index 2afa6dffb96..6da15823244 100644
--- a/libstdc++-v3/libsupc++/atomic_lockfree_defines.h
+++ b/libstdc++-v3/libsupc++/atomic_lockfree_defines.h
@@ -49,6 +49,9 @@
 #define ATOMIC_BOOL_LOCK_FREE		__GCC_ATOMIC_BOOL_LOCK_FREE
 #define ATOMIC_CHAR_LOCK_FREE		__GCC_ATOMIC_CHAR_LOCK_FREE
 #define ATOMIC_WCHAR_T_LOCK_FREE	__GCC_ATOMIC_WCHAR_T_LOCK_FREE
+#ifdef _GLIBCXX_USE_CHAR8_T
+#define ATOMIC_CHAR8_T_LOCK_FREE	__GCC_ATOMIC_CHAR8_T_LOCK_FREE
+#endif
 #define ATOMIC_CHAR16_T_LOCK_FREE	__GCC_ATOMIC_CHAR16_T_LOCK_FREE
 #define ATOMIC_CHAR32_T_LOCK_FREE	__GCC_ATOMIC_CHAR32_T_LOCK_FREE
 #define ATOMIC_SHORT_LOCK_FREE		__GCC_ATOMIC_SHORT_LOCK_FREE
diff --git a/libstdc++-v3/src/c++11/Makefile.am b/libstdc++-v3/src/c++11/Makefile.am
index a22258782cb..d926e172973 100644
--- a/libstdc++-v3/src/c++11/Makefile.am
+++ b/libstdc++-v3/src/c++11/Makefile.am
@@ -126,6 +126,16 @@ hashtable_c++0x.lo: hashtable_c++0x.cc
 hashtable_c++0x.o: hashtable_c++0x.cc
 	$(CXXCOMPILE) -fimplicit-templates -c $<
 
+# Use special rules for source files that require -fchar8_t.
+codecvt.lo: codecvt.cc
+	$(LTCXXCOMPILE) -fchar8_t -c $<
+codecvt.o: codecvt.cc
+	$(CXXCOMPILE) -fchar8_t -c $<
+limits.lo: limits.cc
+	$(LTCXXCOMPILE) -fchar8_t -c $<
+limits.o: limits.cc
+	$(CXXCOMPILE) -fchar8_t -c $<
+
 if ENABLE_DUAL_ABI
 # Rewrite the type info for __ios_failure.
 rewrite_ios_failure_typeinfo = sed -e '/^_*_ZTISt13__ios_failure:/,/_ZTVN10__cxxabiv120__si_class_type_infoE/s/_ZTVN10__cxxabiv120__si_class_type_infoE/_ZTVSt19__iosfail_type_info/'
diff --git a/libstdc++-v3/src/c++11/Makefile.in b/libstdc++-v3/src/c++11/Makefile.in
index d4c4b72a1ae..cec5bfad8ee 100644
--- a/libstdc++-v3/src/c++11/Makefile.in
+++ b/libstdc++-v3/src/c++11/Makefile.in
@@ -751,6 +751,16 @@ hashtable_c++0x.lo: hashtable_c++0x.cc
 hashtable_c++0x.o: hashtable_c++0x.cc
 	$(CXXCOMPILE) -fimplicit-templates -c $<
 
+# Use special rules for source files that require -fchar8_t.
+codecvt.lo: codecvt.cc
+	$(LTCXXCOMPILE) -fchar8_t -c $<
+codecvt.o: codecvt.cc
+	$(CXXCOMPILE) -fchar8_t -c $<
+limits.lo: limits.cc
+	$(LTCXXCOMPILE) -fchar8_t -c $<
+limits.o: limits.cc
+	$(CXXCOMPILE) -fchar8_t -c $<
+
 @ENABLE_DUAL_ABI_TRUE@cxx11-ios_failure-lt.s: cxx11-ios_failure.cc
 @ENABLE_DUAL_ABI_TRUE@	$(LTCXXCOMPILE) -S $< -o tmp-cxx11-ios_failure-lt.s
 @ENABLE_DUAL_ABI_TRUE@	-test -f tmp-cxx11-ios_failure-lt.o && mv -f tmp-cxx11-ios_failure-lt.o tmp-cxx11-ios_failure-lt.s
diff --git a/libstdc++-v3/src/c++11/codecvt.cc b/libstdc++-v3/src/c++11/codecvt.cc
index 503f2fe1ff3..fc9fd427ee5 100644
--- a/libstdc++-v3/src/c++11/codecvt.cc
+++ b/libstdc++-v3/src/c++11/codecvt.cc
@@ -193,8 +193,9 @@ namespace
     }
 
   // If generate_header is set in mode write out UTF-8 BOM.
+  template<typename C>
   bool
-  write_utf8_bom(range<char>& to, codecvt_mode mode)
+  write_utf8_bom(range<C>& to, codecvt_mode mode)
   {
     if (mode & generate_header)
       return write_bom(to, utf8_bom);
@@ -218,8 +219,9 @@ namespace
   }
 
   // If consume_header is set in mode update from.next to after any BOM.
+  template<typename C>
   void
-  read_utf8_bom(range<const char>& from, codecvt_mode mode)
+  read_utf8_bom(range<const C>& from, codecvt_mode mode)
   {
     if (mode & consume_header)
       read_bom(from, utf8_bom);
@@ -245,8 +247,9 @@ namespace
   // Read a codepoint from a UTF-8 multibyte sequence.
   // Updates from.next if the codepoint is not greater than maxcode.
   // Returns invalid_mb_sequence, incomplete_mb_character or the code point.
+  template<typename C>
   char32_t
-  read_utf8_code_point(range<const char>& from, unsigned long maxcode)
+  read_utf8_code_point(range<const C>& from, unsigned long maxcode)
   {
     const size_t avail = from.size();
     if (avail == 0)
@@ -315,8 +318,9 @@ namespace
       return invalid_mb_sequence;
   }
 
+  template<typename C>
   bool
-  write_utf8_code_point(range<char>& to, char32_t code_point)
+  write_utf8_code_point(range<C>& to, char32_t code_point)
   {
     if (code_point < 0x80)
       {
@@ -445,8 +449,9 @@ namespace
   }
 
   // utf8 -> ucs4
+  template<typename C>
   codecvt_base::result
-  ucs4_in(range<const char>& from, range<char32_t>& to,
+  ucs4_in(range<const C>& from, range<char32_t>& to,
           unsigned long maxcode = max_code_point, codecvt_mode mode = {})
   {
     read_utf8_bom(from, mode);
@@ -463,8 +468,9 @@ namespace
   }
 
   // ucs4 -> utf8
+  template<typename C>
   codecvt_base::result
-  ucs4_out(range<const char32_t>& from, range<char>& to,
+  ucs4_out(range<const char32_t>& from, range<C>& to,
            unsigned long maxcode = max_code_point, codecvt_mode mode = {})
   {
     if (!write_utf8_bom(to, mode))
@@ -522,9 +528,9 @@ namespace
   enum class surrogates { allowed, disallowed };
 
   // utf8 -> utf16 (or utf8 -> ucs2 if s == surrogates::disallowed)
-  template<typename C>
+  template<typename C8, typename C16>
   codecvt_base::result
-  utf16_in(range<const char>& from, range<C>& to,
+  utf16_in(range<const C8>& from, range<C16>& to,
 	   unsigned long maxcode = max_code_point, codecvt_mode mode = {},
 	   surrogates s = surrogates::allowed)
   {
@@ -552,9 +558,9 @@ namespace
   }
 
   // utf16 -> utf8 (or ucs2 -> utf8 if s == surrogates::disallowed)
-  template<typename C>
+  template<typename C16, typename C8>
   codecvt_base::result
-  utf16_out(range<const C>& from, range<char>& to,
+  utf16_out(range<const C16>& from, range<C8>& to,
 	    unsigned long maxcode = max_code_point, codecvt_mode mode = {},
 	    surrogates s = surrogates::allowed)
   {
@@ -593,11 +599,12 @@ namespace
   }
 
   // return pos such that [begin,pos) is valid UTF-16 string no longer than max
-  const char*
-  utf16_span(const char* begin, const char* end, size_t max,
+  template<typename C>
+  const C*
+  utf16_span(const C* begin, const C* end, size_t max,
 	     char32_t maxcode = max_code_point, codecvt_mode mode = {})
   {
-    range<const char> from{ begin, end };
+    range<const C> from{ begin, end };
     read_utf8_bom(from, mode);
     size_t count = 0;
     while (count+1 < max)
@@ -615,8 +622,9 @@ namespace
   }
 
   // utf8 -> ucs2
+  template<typename C>
   codecvt_base::result
-  ucs2_in(range<const char>& from, range<char16_t>& to,
+  ucs2_in(range<const C>& from, range<char16_t>& to,
 	  char32_t maxcode = max_code_point, codecvt_mode mode = {})
   {
     // UCS-2 only supports characters in the BMP, i.e. one UTF-16 code unit:
@@ -625,8 +633,9 @@ namespace
   }
 
   // ucs2 -> utf8
+  template<typename C>
   codecvt_base::result
-  ucs2_out(range<const char16_t>& from, range<char>& to,
+  ucs2_out(range<const char16_t>& from, range<C>& to,
 	   char32_t maxcode = max_code_point, codecvt_mode mode = {})
   {
     // UCS-2 only supports characters in the BMP, i.e. one UTF-16 code unit:
@@ -687,11 +696,12 @@ namespace
     return reinterpret_cast<const char16_t*>(from.next);
   }
 
-  const char*
-  ucs2_span(const char* begin, const char* end, size_t max,
+  template<typename C>
+  const C*
+  ucs2_span(const C* begin, const C* end, size_t max,
             char32_t maxcode, codecvt_mode mode)
   {
-    range<const char> from{ begin, end };
+    range<const C> from{ begin, end };
     read_utf8_bom(from, mode);
     // UCS-2 only supports characters in the BMP, i.e. one UTF-16 code unit:
     maxcode = std::min(max_single_utf16_unit, maxcode);
@@ -702,11 +712,12 @@ namespace
   }
 
   // return pos such that [begin,pos) is valid UCS-4 string no longer than max
-  const char*
-  ucs4_span(const char* begin, const char* end, size_t max,
+  template<typename C>
+  const C*
+  ucs4_span(const C* begin, const C* end, size_t max,
             char32_t maxcode = max_code_point, codecvt_mode mode = {})
   {
-    range<const char> from{ begin, end };
+    range<const C> from{ begin, end };
     read_utf8_bom(from, mode);
     char32_t c = 0;
     while (max-- && c <= maxcode)
@@ -875,6 +886,156 @@ codecvt<char32_t, char, mbstate_t>::do_max_length() const throw()
   return 4;
 }
 
+#if defined(_GLIBCXX_USE_CHAR8_T)
+// Define members of codecvt<char16_t, char8_t, mbstate_t> specialization.
+// Converts from UTF-8 to UTF-16.
+
+locale::id codecvt<char16_t, char8_t, mbstate_t>::id;
+
+codecvt<char16_t, char8_t, mbstate_t>::~codecvt() { }
+
+codecvt_base::result
+codecvt<char16_t, char8_t, mbstate_t>::
+do_out(state_type&,
+       const intern_type* __from,
+       const intern_type* __from_end, const intern_type*& __from_next,
+       extern_type* __to, extern_type* __to_end,
+       extern_type*& __to_next) const
+{
+  range<const char16_t> from{ __from, __from_end };
+  range<char8_t> to{ __to, __to_end };
+  auto res = utf16_out(from, to);
+  __from_next = from.next;
+  __to_next = to.next;
+  return res;
+}
+
+codecvt_base::result
+codecvt<char16_t, char8_t, mbstate_t>::
+do_unshift(state_type&, extern_type* __to, extern_type*,
+	   extern_type*& __to_next) const
+{
+  __to_next = __to;
+  return noconv; // we don't use mbstate_t for the unicode facets
+}
+
+codecvt_base::result
+codecvt<char16_t, char8_t, mbstate_t>::
+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
+{
+  range<const char8_t> from{ __from, __from_end };
+  range<char16_t> to{ __to, __to_end };
+#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+  codecvt_mode mode = {};
+#else
+  codecvt_mode mode = little_endian;
+#endif
+  auto res = utf16_in(from, to, max_code_point, mode);
+  __from_next = from.next;
+  __to_next = to.next;
+  return res;
+}
+
+int
+codecvt<char16_t, char8_t, mbstate_t>::do_encoding() const throw()
+{ return 0; } // UTF-8 is not a fixed-width encoding
+
+bool
+codecvt<char16_t, char8_t, mbstate_t>::do_always_noconv() const throw()
+{ return false; }
+
+int
+codecvt<char16_t, char8_t, mbstate_t>::
+do_length(state_type&, const extern_type* __from,
+	  const extern_type* __end, size_t __max) const
+{
+  __end = utf16_span(__from, __end, __max);
+  return __end - __from;
+}
+
+int
+codecvt<char16_t, char8_t, mbstate_t>::do_max_length() const throw()
+{
+  // A single character (one or two UTF-16 code units) requires
+  // up to four UTF-8 code units.
+  return 4;
+}
+
+// Define members of codecvt<char32_t, char8_t, mbstate_t> specialization.
+// Converts from UTF-8 to UTF-32 (aka UCS-4).
+
+locale::id codecvt<char32_t, char8_t, mbstate_t>::id;
+
+codecvt<char32_t, char8_t, mbstate_t>::~codecvt() { }
+
+codecvt_base::result
+codecvt<char32_t, char8_t, mbstate_t>::
+do_out(state_type&, const intern_type* __from, const intern_type* __from_end,
+       const intern_type*& __from_next,
+       extern_type* __to, extern_type* __to_end,
+       extern_type*& __to_next) const
+{
+  range<const char32_t> from{ __from, __from_end };
+  range<char8_t> to{ __to, __to_end };
+  auto res = ucs4_out(from, to);
+  __from_next = from.next;
+  __to_next = to.next;
+  return res;
+}
+
+codecvt_base::result
+codecvt<char32_t, char8_t, mbstate_t>::
+do_unshift(state_type&, extern_type* __to, extern_type*,
+	   extern_type*& __to_next) const
+{
+  __to_next = __to;
+  return noconv;
+}
+
+codecvt_base::result
+codecvt<char32_t, char8_t, mbstate_t>::
+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
+{
+  range<const char8_t> from{ __from, __from_end };
+  range<char32_t> to{ __to, __to_end };
+  auto res = ucs4_in(from, to);
+  __from_next = from.next;
+  __to_next = to.next;
+  return res;
+}
+
+int
+codecvt<char32_t, char8_t, mbstate_t>::do_encoding() const throw()
+{ return 0; } // UTF-8 is not a fixed-width encoding
+
+bool
+codecvt<char32_t, char8_t, mbstate_t>::do_always_noconv() const throw()
+{ return false; }
+
+int
+codecvt<char32_t, char8_t, mbstate_t>::
+do_length(state_type&, const extern_type* __from,
+	  const extern_type* __end, size_t __max) const
+{
+  __end = ucs4_span(__from, __end, __max);
+  return __end - __from;
+}
+
+int
+codecvt<char32_t, char8_t, mbstate_t>::do_max_length() const throw()
+{
+  // A single character (one UTF-32 code unit) requires
+  // up to 4 UTF-8 code units.
+  return 4;
+}
+#endif // _GLIBCXX_USE_CHAR8_T
+
 // Define members of codecvt_utf8<char16_t> base class implementation.
 // Converts from UTF-8 to UCS-2.
 
@@ -1636,5 +1797,12 @@ inline template class __codecvt_abstract_base<char32_t, char, mbstate_t>;
 template class codecvt_byname<char16_t, char, mbstate_t>;
 template class codecvt_byname<char32_t, char, mbstate_t>;
 
+#if defined(_GLIBCXX_USE_CHAR8_T)
+inline template class __codecvt_abstract_base<char16_t, char8_t, mbstate_t>;
+inline template class __codecvt_abstract_base<char32_t, char8_t, mbstate_t>;
+template class codecvt_byname<char16_t, char8_t, mbstate_t>;
+template class codecvt_byname<char32_t, char8_t, mbstate_t>;
+#endif
+
 _GLIBCXX_END_NAMESPACE_VERSION
 }
diff --git a/libstdc++-v3/src/c++11/limits.cc b/libstdc++-v3/src/c++11/limits.cc
index 4d7889f2021..cfb3e5b027e 100644
--- a/libstdc++-v3/src/c++11/limits.cc
+++ b/libstdc++-v3/src/c++11/limits.cc
@@ -525,6 +525,33 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   const bool numeric_limits<long double>::tinyness_before;
   const float_round_style numeric_limits<long double>::round_style;
 
+#ifdef _GLIBCXX_USE_CHAR8_T
+  // char8_t
+  const bool numeric_limits<char8_t>::is_specialized;
+  const int  numeric_limits<char8_t>::digits;
+  const int  numeric_limits<char8_t>::digits10;
+  const int  numeric_limits<char8_t>::max_digits10;
+  const bool numeric_limits<char8_t>::is_signed;
+  const bool numeric_limits<char8_t>::is_integer;
+  const bool numeric_limits<char8_t>::is_exact;
+  const int  numeric_limits<char8_t>::radix;
+  const int  numeric_limits<char8_t>::min_exponent;
+  const int  numeric_limits<char8_t>::min_exponent10;
+  const int  numeric_limits<char8_t>::max_exponent;
+  const int  numeric_limits<char8_t>::max_exponent10;
+  const bool numeric_limits<char8_t>::has_infinity;
+  const bool numeric_limits<char8_t>::has_quiet_NaN;
+  const bool numeric_limits<char8_t>::has_signaling_NaN;
+  const float_denorm_style numeric_limits<char8_t>::has_denorm;
+  const bool numeric_limits<char8_t>::has_denorm_loss;
+  const bool numeric_limits<char8_t>::is_iec559;
+  const bool numeric_limits<char8_t>::is_bounded;
+  const bool numeric_limits<char8_t>::is_modulo;
+  const bool numeric_limits<char8_t>::traps;
+  const bool numeric_limits<char8_t>::tinyness_before;
+  const float_round_style numeric_limits<char8_t>::round_style;
+#endif // _GLIBCXX_USE_CHAR8_T
+
   // char16_t
   const bool numeric_limits<char16_t>::is_specialized;
   const int  numeric_limits<char16_t>::digits;
diff --git a/libstdc++-v3/src/c++98/Makefile.am b/libstdc++-v3/src/c++98/Makefile.am
index bceaa5b0f40..3545ebbac1b 100644
--- a/libstdc++-v3/src/c++98/Makefile.am
+++ b/libstdc++-v3/src/c++98/Makefile.am
@@ -184,13 +184,13 @@ endif
 
 # XXX TODO move locale_init.cc and localename.cc to src/c++11
 locale_init.lo: locale_init.cc
-	$(LTCXXCOMPILE) -std=gnu++11 -c $<
+	$(LTCXXCOMPILE) -std=gnu++11 -fchar8_t -c $<
 locale_init.o: locale_init.cc
-	$(LTCXXCOMPILE) -std=gnu++11 -c $<
+	$(LTCXXCOMPILE) -std=gnu++11 -fchar8_t -c $<
 localename.lo: localename.cc
-	$(LTCXXCOMPILE) -std=gnu++11 -c $<
+	$(LTCXXCOMPILE) -std=gnu++11 -fchar8_t -c $<
 localename.o: localename.cc
-	$(LTCXXCOMPILE) -std=gnu++11 -c $<
+	$(LTCXXCOMPILE) -std=gnu++11 -fchar8_t -c $<
 
 # Use special rules for the deprecated source files so that they find
 # deprecated include files.
diff --git a/libstdc++-v3/src/c++98/Makefile.in b/libstdc++-v3/src/c++98/Makefile.in
index 33f2ac0f87a..53c8592a6cd 100644
--- a/libstdc++-v3/src/c++98/Makefile.in
+++ b/libstdc++-v3/src/c++98/Makefile.in
@@ -805,13 +805,13 @@ c++locale.o: c++locale.cc
 
 # XXX TODO move locale_init.cc and localename.cc to src/c++11
 locale_init.lo: locale_init.cc
-	$(LTCXXCOMPILE) -std=gnu++11 -c $<
+	$(LTCXXCOMPILE) -std=gnu++11 -fchar8_t -c $<
 locale_init.o: locale_init.cc
-	$(LTCXXCOMPILE) -std=gnu++11 -c $<
+	$(LTCXXCOMPILE) -std=gnu++11 -fchar8_t -c $<
 localename.lo: localename.cc
-	$(LTCXXCOMPILE) -std=gnu++11 -c $<
+	$(LTCXXCOMPILE) -std=gnu++11 -fchar8_t -c $<
 localename.o: localename.cc
-	$(LTCXXCOMPILE) -std=gnu++11 -c $<
+	$(LTCXXCOMPILE) -std=gnu++11 -fchar8_t -c $<
 strstream.lo: strstream.cc
 	$(LTCXXCOMPILE) -I$(GLIBCXX_INCLUDE_DIR)/backward -Wno-deprecated -c $<
 strstream.o: strstream.cc
diff --git a/libstdc++-v3/src/c++98/locale_init.cc b/libstdc++-v3/src/c++98/locale_init.cc
index b580a9f9d58..edf4ca8fd8e 100644
--- a/libstdc++-v3/src/c++98/locale_init.cc
+++ b/libstdc++-v3/src/c++98/locale_init.cc
@@ -209,6 +209,16 @@ namespace
   __attribute__ ((aligned(__alignof__(codecvt<char32_t, char, mbstate_t>))));
   fake_codecvt_c32 codecvt_c32;
 
+#ifdef _GLIBCXX_USE_CHAR8_T
+  typedef char fake_codecvt_c16_c8[sizeof(codecvt<char16_t, char8_t, mbstate_t>)]
+  __attribute__ ((aligned(__alignof__(codecvt<char16_t, char8_t, mbstate_t>))));
+  fake_codecvt_c16_c8 codecvt_c16_c8;
+
+  typedef char fake_codecvt_c32_c8[sizeof(codecvt<char32_t, char8_t, mbstate_t>)]
+  __attribute__ ((aligned(__alignof__(codecvt<char32_t, char8_t, mbstate_t>))));
+  fake_codecvt_c32_c8 codecvt_c32_c8;
+#endif
+
   // Storage for "C" locale caches.
   typedef char fake_num_cache_c[sizeof(std::__numpunct_cache<char>)]
   __attribute__ ((aligned(__alignof__(std::__numpunct_cache<char>))));
@@ -329,6 +339,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #if _GLIBCXX_NUM_UNICODE_FACETS != 0
     &codecvt<char16_t, char, mbstate_t>::id,
     &codecvt<char32_t, char, mbstate_t>::id,
+#ifdef _GLIBCXX_USE_CHAR8_T
+    &codecvt<char16_t, char8_t, mbstate_t>::id,
+    &codecvt<char32_t, char8_t, mbstate_t>::id,
+#endif
 #endif
     0
   };
@@ -536,6 +550,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #if _GLIBCXX_NUM_UNICODE_FACETS != 0
     _M_init_facet(new (&codecvt_c16) codecvt<char16_t, char, mbstate_t>(1));
     _M_init_facet(new (&codecvt_c32) codecvt<char32_t, char, mbstate_t>(1));
+
+#ifdef _GLIBCXX_USE_CHAR8_T
+    _M_init_facet(new (&codecvt_c16_c8) codecvt<char16_t, char8_t, mbstate_t>(1));
+    _M_init_facet(new (&codecvt_c32_c8) codecvt<char32_t, char8_t, mbstate_t>(1));
+#endif
+
 #endif
 
 #if _GLIBCXX_USE_DUAL_ABI
diff --git a/libstdc++-v3/src/c++98/localename.cc b/libstdc++-v3/src/c++98/localename.cc
index afb43e5cea9..aa66ae207a3 100644
--- a/libstdc++-v3/src/c++98/localename.cc
+++ b/libstdc++-v3/src/c++98/localename.cc
@@ -272,6 +272,12 @@ const int num_facets = _GLIBCXX_NUM_FACETS + _GLIBCXX_NUM_UNICODE_FACETS
 #if _GLIBCXX_NUM_UNICODE_FACETS != 0
         _M_init_facet(new codecvt<char16_t, char, mbstate_t>);
         _M_init_facet(new codecvt<char32_t, char, mbstate_t>);
+
+#ifdef _GLIBCXX_USE_CHAR8_T
+        _M_init_facet(new codecvt<char16_t, char8_t, mbstate_t>);
+        _M_init_facet(new codecvt<char32_t, char8_t, mbstate_t>);
+#endif
+
 #endif
 
 #if _GLIBCXX_USE_DUAL_ABI
diff --git a/libstdc++-v3/testsuite/util/testsuite_abi.cc b/libstdc++-v3/testsuite/util/testsuite_abi.cc
index c9aaf74133f..f45bcf46fac 100644
--- a/libstdc++-v3/testsuite/util/testsuite_abi.cc
+++ b/libstdc++-v3/testsuite/util/testsuite_abi.cc
@@ -220,6 +220,7 @@ check_version(symbol& test, bool added)
       known_versions.push_back("CXXABI_1.3.9");
       known_versions.push_back("CXXABI_1.3.10");
       known_versions.push_back("CXXABI_1.3.11");
+      known_versions.push_back("CXXABI_1.3.12");
       known_versions.push_back("CXXABI_TM_1");
       known_versions.push_back("CXXABI_FLOAT128");
     }
@@ -238,7 +239,7 @@ check_version(symbol& test, bool added)
 
       // Check that added symbols are added in the latest pre-release version.
       bool latestp = (test.version_name == "GLIBCXX_3.4.26"
-		     || test.version_name == "CXXABI_1.3.11"
+		     || test.version_name == "CXXABI_1.3.12"
 		     || test.version_name == "CXXABI_FLOAT128"
 		     || test.version_name == "CXXABI_TM_1");
       if (added && !latestp)
Jonathan Wakely Feb. 7, 2019, 9:44 a.m. UTC | #2
On 23/12/18 21:27 -0500, Tom Honermann wrote:
>Attached is a revised patch that addresses changes in P0482R6.  
>Changes from the prior patch include:
>- Updated the value of the __cpp_char8_t feature test macro to 201811.
>
>Tested on x86_64-linux.

Thanks, Tom, this is great work!

The front-end changes for char8_t went in recently, and I'm finally
ready to commit the library parts. There's one big problem I found in
this patch, which is that the new numeric_limits<char8_t>
specialization uses constexpr unconditionally. That fails if <limits>
is compiled using options like -std=c++98 -fno-char8_t because the
specialization will be used, but the constexpr keyword isn't allowed.
That's easily fixed by replacing the keyword with _GLIBCXX_CONSTEXPR.

The other way to solve that problem would be for the compiler to give
an error if -fchar8_t is used with C++98, but I see no fundamental
reason that combination of options shouldn't be allowed. We can
support it in the library by using the macro.

As discussed in San Diego, the other change needed is to add the
abi_tag attribute to the new versions of path::u8string and
path::generic_u8string, so that the mangling is different when its
return type is different:

#ifdef _GLIBCXX_USE_CHAR8_T
    __attribute__((__abi_tag__("__u8")))
    std::u8string  u8string() const;
#else
    std::string    u8string() const;
#endif // _GLIBCXX_USE_CHAR8_T

Otherwise we get ODR violations when linking objects compiled
with -fchar8_t enabled to objects with it disabled (e.g. linking
-std=c++17 objects to -std=c++2a objects, which needs to work).

I suggest "__u8" as the name of the ABI tag, but I'm open to other
suggestions. "__char8_t" is a bit long and verbose. "__cxx20" would be
consistent with "__cxx11" used for the new ABI introduced in GCC 5 but
it regularly confuses people who think it is coupled to the -std=c++11
option (and so don't understand why they still see it for -std=c++14).

Also, I see that you've made changes to <experimental/string_view> (to
add the experimental::u8string_view typedef) and to
std::experimental::path (to change the return type of u8string and
generic_u8string).

The former change is fairly harmless; it only adds a typedef, albeit
one which is not a reserved name in C++14/C++17 and so should be
available for users to define as a macro. Maybe prior to C++2a we
should only define it when GNU extensions are enabled (i.e. when using
-std=gnu++14 not -std=c++14):

#if defined _GLIBCXX_USE_CHAR8_T \
  && (__cplusplus > 201703L || !defined __STRICT_ANSI__)
  using u8string_view = basic_string_view<char8_t>;
#endif

Changing the return type of experimental::path members concerns me
more. That's a published TS which is not going to be revised, and it's
not obvious to me that users would want the change in semantics. If
somebody is still using the Filesystem TS in C++2a code, they're
probably not expecting it to change. If they need to update their code
for C++2a they might as well just use std::filesystem, and so having
char8_t support in std::experimental::filesystem isn't clearly useful.
Tom Honermann Feb. 8, 2019, 4:35 a.m. UTC | #3
On 2/7/19 4:44 AM, Jonathan Wakely wrote:
> On 23/12/18 21:27 -0500, Tom Honermann wrote:
>> Attached is a revised patch that addresses changes in P0482R6.  
>> Changes from the prior patch include:
>> - Updated the value of the __cpp_char8_t feature test macro to 201811.
>>
>> Tested on x86_64-linux.
>
> Thanks, Tom, this is great work!
>
> The front-end changes for char8_t went in recently, and I'm finally
> ready to commit the library parts.
Great!
> There's one big problem I found in
> this patch, which is that the new numeric_limits<char8_t>
> specialization uses constexpr unconditionally. That fails if <limits>
> is compiled using options like -std=c++98 -fno-char8_t because the
> specialization will be used, but the constexpr keyword isn't allowed.
> That's easily fixed by replacing the keyword with _GLIBCXX_CONSTEXPR.
Hmm, the code for the char8_t specialization was copied from the 
char16_t specialization which also uses constexpr unconditionally (but 
is guarded by a C++11+ requirement).  The char8_t specialization must be 
elided when the compiler is invoked with -std=c++98 -fno-char8_t (since 
the char8_t type doesn't exist then).  The _GLIBCXX_USE_CHAR8_T guard 
doesn't suffice for this? _GLIBCXX_USE_CHAR8_T should only be defined if 
__cpp_char8_t is defined; and that should only be defined if -fchar8_t 
or -std=c++2a is specified.  Or perhaps you intended -std=c++98 
-fchar8_t?  I agree in that case that use of _GLIBCXX_CONSTEXPR is 
necessary.
>
> The other way to solve that problem would be for the compiler to give
> an error if -fchar8_t is used with C++98, but I see no fundamental
> reason that combination of options shouldn't be allowed. We can
> support it in the library by using the macro.
Agreed.
>
> As discussed in San Diego, the other change needed is to add the
> abi_tag attribute to the new versions of path::u8string and
> path::generic_u8string, so that the mangling is different when its
> return type is different:
>
> #ifdef _GLIBCXX_USE_CHAR8_T
>    __attribute__((__abi_tag__("__u8")))
>    std::u8string  u8string() const;
> #else
>    std::string    u8string() const;
> #endif // _GLIBCXX_USE_CHAR8_T
>
> Otherwise we get ODR violations when linking objects compiled
> with -fchar8_t enabled to objects with it disabled (e.g. linking
> -std=c++17 objects to -std=c++2a objects, which needs to work).

Are ODR violations bad? :)

>
> I suggest "__u8" as the name of the ABI tag, but I'm open to other
> suggestions. "__char8_t" is a bit long and verbose. "__cxx20" would be
> consistent with "__cxx11" used for the new ABI introduced in GCC 5 but
> it regularly confuses people who think it is coupled to the -std=c++11
> option (and so don't understand why they still see it for -std=c++14).
I have no preference or alternative suggestions here.  Had I recognized 
the issue, I would have asked you what to do about it :)
>
> Also, I see that you've made changes to <experimental/string_view> (to
> add the experimental::u8string_view typedef) and to
> std::experimental::path (to change the return type of u8string and
> generic_u8string).
>
> The former change is fairly harmless; it only adds a typedef, albeit
> one which is not a reserved name in C++14/C++17 and so should be
> available for users to define as a macro. Maybe prior to C++2a we
> should only define it when GNU extensions are enabled (i.e. when using
> -std=gnu++14 not -std=c++14):
>
> #if defined _GLIBCXX_USE_CHAR8_T \
>  && (__cplusplus > 201703L || !defined __STRICT_ANSI__)
>  using u8string_view = basic_string_view<char8_t>;
> #endif
That makes sense.
>
> Changing the return type of experimental::path members concerns me
> more. That's a published TS which is not going to be revised, and it's
> not obvious to me that users would want the change in semantics. If
> somebody is still using the Filesystem TS in C++2a code, they're
> probably not expecting it to change. If they need to update their code
> for C++2a they might as well just use std::filesystem, and so having
> char8_t support in std::experimental::filesystem isn't clearly useful.
>
I agree.  I added the support to the experimental implementations more 
out of a desire to be complete and to remove any potential barriers to 
use of -fchar8_t than because I felt the changes were really necessary.  
I would be perfectly fine with skipping the updates to the experimental 
libraries completely.

Tom.
Jonathan Wakely Feb. 8, 2019, 12:56 p.m. UTC | #4
On 07/02/19 23:35 -0500, Tom Honermann wrote:
>On 2/7/19 4:44 AM, Jonathan Wakely wrote:
>>On 23/12/18 21:27 -0500, Tom Honermann wrote:
>>>Attached is a revised patch that addresses changes in P0482R6.  
>>>Changes from the prior patch include:
>>>- Updated the value of the __cpp_char8_t feature test macro to 201811.
>>>
>>>Tested on x86_64-linux.
>>
>>Thanks, Tom, this is great work!
>>
>>The front-end changes for char8_t went in recently, and I'm finally
>>ready to commit the library parts.
>Great!
>>There's one big problem I found in
>>this patch, which is that the new numeric_limits<char8_t>
>>specialization uses constexpr unconditionally. That fails if <limits>
>>is compiled using options like -std=c++98 -fno-char8_t because the
>>specialization will be used, but the constexpr keyword isn't allowed.
>>That's easily fixed by replacing the keyword with _GLIBCXX_CONSTEXPR.
>Hmm, the code for the char8_t specialization was copied from the 
>char16_t specialization which also uses constexpr unconditionally (but 
>is guarded by a C++11+ requirement).

That can use it unconditionally, because there's no -fchar16_t switch
to enable char16_t prior to C++11.

>The char8_t specialization must 
>be elided when the compiler is invoked with -std=c++98 -fno-char8_t 
>(since the char8_t type doesn't exist then).  The _GLIBCXX_USE_CHAR8_T 
>guard doesn't suffice for this? _GLIBCXX_USE_CHAR8_T should only be 
>defined if __cpp_char8_t is defined; and that should only be defined 
>if -fchar8_t or -std=c++2a is specified.  Or perhaps you intended 
>-std=c++98 -fchar8_t?  I agree in that case that use of 
>_GLIBCXX_CONSTEXPR is necessary.

Yes sorry, that's a typo above, I meant -std=c++98 -fchar8_t.

The -std=c++98 -fno-char8_t case works fine, as expected (because
-fno-char8_t is the default for -std=c++98 anyway).

>>The other way to solve that problem would be for the compiler to give
>>an error if -fchar8_t is used with C++98, but I see no fundamental
>>reason that combination of options shouldn't be allowed. We can
>>support it in the library by using the macro.
>Agreed.
>>
>>As discussed in San Diego, the other change needed is to add the
>>abi_tag attribute to the new versions of path::u8string and
>>path::generic_u8string, so that the mangling is different when its
>>return type is different:
>>
>>#ifdef _GLIBCXX_USE_CHAR8_T
>>   __attribute__((__abi_tag__("__u8")))
>>   std::u8string  u8string() const;
>>#else
>>   std::string    u8string() const;
>>#endif // _GLIBCXX_USE_CHAR8_T
>>
>>Otherwise we get ODR violations when linking objects compiled
>>with -fchar8_t enabled to objects with it disabled (e.g. linking
>>-std=c++17 objects to -std=c++2a objects, which needs to work).
>
>Are ODR violations bad? :)

Only when they make people send us bug reports ;-)

>>
>>I suggest "__u8" as the name of the ABI tag, but I'm open to other
>>suggestions. "__char8_t" is a bit long and verbose. "__cxx20" would be
>>consistent with "__cxx11" used for the new ABI introduced in GCC 5 but
>>it regularly confuses people who think it is coupled to the -std=c++11
>>option (and so don't understand why they still see it for -std=c++14).
>I have no preference or alternative suggestions here.  Had I 
>recognized the issue, I would have asked you what to do about it :)
>>
>>Also, I see that you've made changes to <experimental/string_view> (to
>>add the experimental::u8string_view typedef) and to
>>std::experimental::path (to change the return type of u8string and
>>generic_u8string).
>>
>>The former change is fairly harmless; it only adds a typedef, albeit
>>one which is not a reserved name in C++14/C++17 and so should be
>>available for users to define as a macro. Maybe prior to C++2a we
>>should only define it when GNU extensions are enabled (i.e. when using
>>-std=gnu++14 not -std=c++14):
>>
>>#if defined _GLIBCXX_USE_CHAR8_T \
>> && (__cplusplus > 201703L || !defined __STRICT_ANSI__)
>> using u8string_view = basic_string_view<char8_t>;
>>#endif
>That makes sense.

Actually I was thinking about this further, and if somebody explicitly
uses -fchar8_t then they're asking for a non-standard dialect of C++
anyway, and so they can't complain about some extra non-standard
names. So I think it's fine to declare std::u8string_view whenever
char8_t is enabled.

>>Changing the return type of experimental::path members concerns me
>>more. That's a published TS which is not going to be revised, and it's
>>not obvious to me that users would want the change in semantics. If
>>somebody is still using the Filesystem TS in C++2a code, they're
>>probably not expecting it to change. If they need to update their code
>>for C++2a they might as well just use std::filesystem, and so having
>>char8_t support in std::experimental::filesystem isn't clearly useful.
>>
>I agree.  I added the support to the experimental implementations more 
>out of a desire to be complete and to remove any potential barriers to 
>use of -fchar8_t than because I felt the changes were really 
>necessary.  I would be perfectly fine with skipping the updates to the 
>experimental libraries completely.

OK, let's leave them alone.
Jonathan Wakely Feb. 19, 2019, 2:54 a.m. UTC | #5
On 08/02/19 12:56 +0000, Jonathan Wakely wrote:
>On 07/02/19 23:35 -0500, Tom Honermann wrote:
>>On 2/7/19 4:44 AM, Jonathan Wakely wrote:
>>>On 23/12/18 21:27 -0500, Tom Honermann wrote:
>>>>Attached is a revised patch that addresses changes in P0482R6.  
>>>>Changes from the prior patch include:
>>>>- Updated the value of the __cpp_char8_t feature test macro to 201811.
>>>>
>>>>Tested on x86_64-linux.
>>>
>>>Thanks, Tom, this is great work!
>>>
>>>The front-end changes for char8_t went in recently, and I'm finally
>>>ready to commit the library parts.
>>Great!
>>>There's one big problem I found in
>>>this patch, which is that the new numeric_limits<char8_t>
>>>specialization uses constexpr unconditionally. That fails if <limits>
>>>is compiled using options like -std=c++98 -fno-char8_t because the
>>>specialization will be used, but the constexpr keyword isn't allowed.
>>>That's easily fixed by replacing the keyword with _GLIBCXX_CONSTEXPR.
>>Hmm, the code for the char8_t specialization was copied from the 
>>char16_t specialization which also uses constexpr unconditionally 
>>(but is guarded by a C++11+ requirement).
>
>That can use it unconditionally, because there's no -fchar16_t switch
>to enable char16_t prior to C++11.
>
>>The char8_t specialization must be elided when the compiler is 
>>invoked with -std=c++98 -fno-char8_t (since the char8_t type doesn't 
>>exist then).  The _GLIBCXX_USE_CHAR8_T guard doesn't suffice for 
>>this? _GLIBCXX_USE_CHAR8_T should only be defined if __cpp_char8_t 
>>is defined; and that should only be defined if -fchar8_t or 
>>-std=c++2a is specified.  Or perhaps you intended -std=c++98 
>>-fchar8_t?  I agree in that case that use of _GLIBCXX_CONSTEXPR is 
>>necessary.
>
>Yes sorry, that's a typo above, I meant -std=c++98 -fchar8_t.
>
>The -std=c++98 -fno-char8_t case works fine, as expected (because
>-fno-char8_t is the default for -std=c++98 anyway).
>
>>>The other way to solve that problem would be for the compiler to give
>>>an error if -fchar8_t is used with C++98, but I see no fundamental
>>>reason that combination of options shouldn't be allowed. We can
>>>support it in the library by using the macro.
>>Agreed.
>>>
>>>As discussed in San Diego, the other change needed is to add the
>>>abi_tag attribute to the new versions of path::u8string and
>>>path::generic_u8string, so that the mangling is different when its
>>>return type is different:
>>>
>>>#ifdef _GLIBCXX_USE_CHAR8_T
>>>   __attribute__((__abi_tag__("__u8")))
>>>   std::u8string  u8string() const;
>>>#else
>>>   std::string    u8string() const;
>>>#endif // _GLIBCXX_USE_CHAR8_T
>>>
>>>Otherwise we get ODR violations when linking objects compiled
>>>with -fchar8_t enabled to objects with it disabled (e.g. linking
>>>-std=c++17 objects to -std=c++2a objects, which needs to work).
>>
>>Are ODR violations bad? :)
>
>Only when they make people send us bug reports ;-)
>
>>>
>>>I suggest "__u8" as the name of the ABI tag, but I'm open to other
>>>suggestions. "__char8_t" is a bit long and verbose. "__cxx20" would be
>>>consistent with "__cxx11" used for the new ABI introduced in GCC 5 but
>>>it regularly confuses people who think it is coupled to the -std=c++11
>>>option (and so don't understand why they still see it for -std=c++14).
>>I have no preference or alternative suggestions here.  Had I 
>>recognized the issue, I would have asked you what to do about it :)
>>>
>>>Also, I see that you've made changes to <experimental/string_view> (to
>>>add the experimental::u8string_view typedef) and to
>>>std::experimental::path (to change the return type of u8string and
>>>generic_u8string).
>>>
>>>The former change is fairly harmless; it only adds a typedef, albeit
>>>one which is not a reserved name in C++14/C++17 and so should be
>>>available for users to define as a macro. Maybe prior to C++2a we
>>>should only define it when GNU extensions are enabled (i.e. when using
>>>-std=gnu++14 not -std=c++14):
>>>
>>>#if defined _GLIBCXX_USE_CHAR8_T \
>>> && (__cplusplus > 201703L || !defined __STRICT_ANSI__)
>>> using u8string_view = basic_string_view<char8_t>;
>>>#endif
>>That makes sense.
>
>Actually I was thinking about this further, and if somebody explicitly
>uses -fchar8_t then they're asking for a non-standard dialect of C++
>anyway, and so they can't complain about some extra non-standard
>names. So I think it's fine to declare std::u8string_view whenever
>char8_t is enabled.
>
>>>Changing the return type of experimental::path members concerns me
>>>more. That's a published TS which is not going to be revised, and it's
>>>not obvious to me that users would want the change in semantics. If
>>>somebody is still using the Filesystem TS in C++2a code, they're
>>>probably not expecting it to change. If they need to update their code
>>>for C++2a they might as well just use std::filesystem, and so having
>>>char8_t support in std::experimental::filesystem isn't clearly useful.
>>>
>>I agree.  I added the support to the experimental implementations 
>>more out of a desire to be complete and to remove any potential 
>>barriers to use of -fchar8_t than because I felt the changes were 
>>really necessary.  I would be perfectly fine with skipping the 
>>updates to the experimental libraries completely.
>
>OK, let's leave them alone.

Here's what I'm committing to trunk.
commit 42b548f7f9dfe60aa3add0e7990f19c385173f0f
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Wed Feb 6 21:08:42 2019 +0000

    P0482R5 char8_t: Standard library support
    
    gcc/cp:
    
    2019-02-19  Tom Honermann  <tom@honermann.net>
    
            * name-lookup.c (get_std_name_hint): Added u8string as a name hint.
    
    libstdc++:
    
    2019-02-19  Tom Honermann  <tom@honermann.net>
    
            P0482R5 char8_t: Standard library support
            * config/abi/pre/gnu-versioned-namespace.ver (CXXABI_2.0): Add
            typeinfo symbols for char8_t.
            * config/abi/pre/gnu.ver: Add CXXABI_1.3.12.
            (GLIBCXX_3.4.26): Add symbols for specializations of
            numeric_limits and codecvt that involve char8_t.
            (CXXABI_1.3.12): Add typeinfo symbols for char8_t.
            * include/bits/atomic_base.h: Add atomic_char8_t.
            * include/bits/basic_string.h: Add std::hash<u8string> and
            operator""s(const char8_t*, size_t).
            * include/bits/c++config: Define _GLIBCXX_USE_CHAR8_T and
            __cpp_lib_char8_t.
            * include/bits/char_traits.h: Add char_traits<char8_t>.
            * include/bits/codecvt.h: Add
            codecvt<char16_t, char8_t, mbstate_t>,
            codecvt<char32_t, char8_t, mbstate_t>,
            codecvt_byname<char16_t, char8_t, mbstate_t>, and
            codecvt_byname<char32_t, char8_t, mbstate_t>.
            * include/bits/cpp_type_traits.h: Add __is_integer<char8_t> to
            recognize char8_t as an integral type.
            * include/bits/fs_path.h: (path::__is_encoded_char): Recognize
            char8_t.
            (path::u8string): Return std::u8string when char8_t support is
            enabled.
            (path::generic_u8string): Likewise.
            (path::_S_convert): Handle conversion from char8_t input.
            (path::_S_str_convert): Likewise.
            * include/bits/functional_hash.h: Add hash<char8_t>.
            * include/bits/locale_conv.h (__str_codecvt_out): Add overloads for
            char8_t.
            * include/bits/locale_facets.h (_GLIBCXX_NUM_UNICODE_FACETS): Bump
            for new char8_t specializations.
            * include/bits/localefwd.h: Add missing declarations of
            codecvt<char16_t, char, mbstate_t> and
            codecvt<char32_t, char, mbstate_t>.  Add char8_t declarations
            codecvt<char16_t, char8_t, mbstate_t> and
            codecvt<char32_t, char8_t, mbstate_t>.
            * include/bits/postypes.h: Add u8streampos
            * include/bits/stringfwd.h: Add declarations of
            char_traits<char8_t> and u8string.
            * include/c_global/cstddef: Add __byte_operand<char8_t>.
            * include/experimental/bits/fs_path.h (path::__is_encoded_char):
            Recognize char8_t.
            (path::u8string): Return std::u8string when char8_t support is
            enabled.
            (path::generic_u8string): Likewise.
            (path::_S_convert): Handle conversion from char8_t input.
            (path::_S_str_convert): Likewise.
            * include/experimental/string: Add u8string.
            * include/experimental/string_view: Add u8string_view,
            hash<experimental::u8string_view>, and
            operator""sv(const char8_t*, size_t).
            * include/std/atomic: Add atomic<char8_t> and atomic_char8_t.
            * include/std/charconv (__is_int_to_chars_type): Recognize char8_t
            as a character type.
            * include/std/limits: Add numeric_limits<char8_t>.
            * include/std/string_view: Add u8string_view,
            hash<experimental::u8string_view>, and
            operator""sv(const char8_t*, size_t).
            * include/std/type_traits: Add __is_integral_helper<char8_t>,
            __make_unsigned<char8_t>, and __make_signed<char8_t>.
            * libsupc++/atomic_lockfree_defines.h: Define
            ATOMIC_CHAR8_T_LOCK_FREE.
            * src/c++11/Makefile.am: Compile with -fchar8_t when compiling
            codecvt.cc and limits.cc so that char8_t specializations of
            numeric_limits and codecvt and emitted.
            * src/c++11/Makefile.in: Likewise.
            * src/c++11/codecvt.cc: Define members of
            codecvt<char16_t, char8_t, mbstate_t>,
            codecvt<char32_t, char8_t, mbstate_t>,
            codecvt_byname<char16_t, char8_t, mbstate_t>, and
            codecvt_byname<char32_t, char8_t, mbstate_t>.
            * src/c++11/limits.cc: Define members of
            numeric_limits<char8_t>.
            * src/c++98/Makefile.am: Compile with -fchar8_t when compiling
            locale_init.cc and localename.cc.
            * src/c++98/Makefile.in: Likewise.
            * src/c++98/locale_init.cc: Add initialization for the
            codecvt<char16_t, char8_t, mbstate_t> and
            codecvt<char32_t, char8_t, mbstate_t> facets.
            * src/c++98/localename.cc: Likewise.
            * testsuite/util/testsuite_abi.cc: Validate ABI bump.

diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c
index 959f43b0238..2e1b851341b 100644
--- a/gcc/cp/name-lookup.c
+++ b/gcc/cp/name-lookup.c
@@ -5765,6 +5765,7 @@ get_std_name_hint (const char *name)
     {"basic_string", "<string>", cxx98},
     {"string", "<string>", cxx98},
     {"wstring", "<string>", cxx98},
+    {"u8string", "<string>", cxx2a},
     {"u16string", "<string>", cxx11},
     {"u32string", "<string>", cxx11},
     /* <string_view>.  */
diff --git a/libstdc++-v3/config/abi/pre/gnu-versioned-namespace.ver b/libstdc++-v3/config/abi/pre/gnu-versioned-namespace.ver
index d776bf09687..e6079ad2cf3 100644
--- a/libstdc++-v3/config/abi/pre/gnu-versioned-namespace.ver
+++ b/libstdc++-v3/config/abi/pre/gnu-versioned-namespace.ver
@@ -301,6 +301,11 @@ CXXABI_2.0 {
     _ZTSN10__cxxabiv120__si_class_type_infoE;
     _ZTSN10__cxxabiv121__vmi_class_type_infoE;
 
+    # typeinfo for char8_t
+    _ZTIDu;
+    _ZTIPDu;
+    _ZTIPKDu;
+
     # typeinfo for char16_t and char32_t
     _ZTIDs;
     _ZTIPDs;
diff --git a/libstdc++-v3/config/abi/pre/gnu.ver b/libstdc++-v3/config/abi/pre/gnu.ver
index a0860668b90..c4f12152147 100644
--- a/libstdc++-v3/config/abi/pre/gnu.ver
+++ b/libstdc++-v3/config/abi/pre/gnu.ver
@@ -2244,6 +2244,17 @@ GLIBCXX_3.4.26 {
     # _Sp_make_shared_tag::_S_eq
     _ZNSt19_Sp_make_shared_tag5_S_eqERKSt9type_info;
 
+    # numeric_limits<char8_t>
+    _ZNSt14numeric_limitsIDuE[5-9]*;
+    _ZNSt14numeric_limitsIDuE1[0-7][hirt]*;
+    _ZNSt14numeric_limitsIDuE1[0-7]mi*;
+    _ZNSt14numeric_limitsIDuE1[0-7]max_e*;
+
+    # codecvt<char16_t, char8_t, mbstate_t>, codecvt<char32_t, char8_t, mbstate_t>
+    _ZNKSt7codecvtID[is]Du*;
+    _ZNSt7codecvtID[is]Du*;
+    _ZT[ISV]St7codecvtID[is]Du*E;
+
 } GLIBCXX_3.4.25;
 
 # Symbols in the support library (libsupc++) have their own tag.
@@ -2535,6 +2546,15 @@ CXXABI_1.3.11 {
 
 } CXXABI_1.3.10;
 
+CXXABI_1.3.12 {
+
+    # typeinfo for char8_t
+    _ZTIDu;
+    _ZTIPDu;
+    _ZTIPKDu;
+
+} CXXABI_1.3.11;
+
 # Symbols in the support library (libsupc++) supporting transactional memory.
 CXXABI_TM_1 {
 
diff --git a/libstdc++-v3/include/bits/atomic_base.h b/libstdc++-v3/include/bits/atomic_base.h
index 78eb5d6a1d4..fd2ea718015 100644
--- a/libstdc++-v3/include/bits/atomic_base.h
+++ b/libstdc++-v3/include/bits/atomic_base.h
@@ -227,6 +227,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   // atomic_ulong    unsigned long
   // atomic_llong    long long
   // atomic_ullong   unsigned long long
+  // atomic_char8_t  char8_t
   // atomic_char16_t char16_t
   // atomic_char32_t char32_t
   // atomic_wchar_t  wchar_t
diff --git a/libstdc++-v3/include/bits/basic_string.h b/libstdc++-v3/include/bits/basic_string.h
index 0a6dd3cbc71..4d0894be99b 100644
--- a/libstdc++-v3/include/bits/basic_string.h
+++ b/libstdc++-v3/include/bits/basic_string.h
@@ -6753,6 +6753,23 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #endif
 #endif /* _GLIBCXX_COMPATIBILITY_CXX0X */
 
+#ifdef _GLIBCXX_USE_CHAR8_T
+  /// std::hash specialization for u8string.
+  template<>
+    struct hash<u8string>
+    : public __hash_base<size_t, u8string>
+    {
+      size_t
+      operator()(const u8string& __s) const noexcept
+      { return std::_Hash_impl::hash(__s.data(),
+                                     __s.length() * sizeof(char8_t)); }
+    };
+
+  template<>
+    struct __is_fast_hash<hash<u8string>> : std::false_type
+    { };
+#endif
+
   /// std::hash specialization for u16string.
   template<>
     struct hash<u16string>
@@ -6805,6 +6822,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { return basic_string<wchar_t>{__str, __len}; }
 #endif
 
+#ifdef _GLIBCXX_USE_CHAR8_T
+    _GLIBCXX_DEFAULT_ABI_TAG
+    inline basic_string<char8_t>
+    operator""s(const char8_t* __str, size_t __len)
+    { return basic_string<char8_t>{__str, __len}; }
+#endif
+
     _GLIBCXX_DEFAULT_ABI_TAG
     inline basic_string<char16_t>
     operator""s(const char16_t* __str, size_t __len)
diff --git a/libstdc++-v3/include/bits/c++config b/libstdc++-v3/include/bits/c++config
index 97bb6db70b1..9993f4b1998 100644
--- a/libstdc++-v3/include/bits/c++config
+++ b/libstdc++-v3/include/bits/c++config
@@ -625,6 +625,17 @@ namespace std
 # endif
 #endif
 
+// Unless explicitly specified, enable char8_t extensions only if the core
+// language char8_t feature macro is defined.
+#ifndef _GLIBCXX_USE_CHAR8_T
+# ifdef __cpp_char8_t
+#  define _GLIBCXX_USE_CHAR8_T 1
+# endif
+#endif
+#ifdef _GLIBCXX_USE_CHAR8_T
+# define __cpp_lib_char8_t 201811
+#endif
+
 /* Define if __float128 is supported on this host. */
 #if defined(__FLOAT128__) || defined(__SIZEOF_FLOAT128__)
 #define _GLIBCXX_USE_FLOAT128
diff --git a/libstdc++-v3/include/bits/char_traits.h b/libstdc++-v3/include/bits/char_traits.h
index d91fe84063b..21099c36c3b 100644
--- a/libstdc++-v3/include/bits/char_traits.h
+++ b/libstdc++-v3/include/bits/char_traits.h
@@ -507,6 +507,115 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   };
 #endif //_GLIBCXX_USE_WCHAR_T
 
+#ifdef _GLIBCXX_USE_CHAR8_T
+  template<>
+    struct char_traits<char8_t>
+    {
+      typedef char8_t           char_type;
+      typedef unsigned int      int_type;
+      typedef u8streampos       pos_type;
+      typedef streamoff         off_type;
+      typedef mbstate_t         state_type;
+
+      static _GLIBCXX17_CONSTEXPR void
+      assign(char_type& __c1, const char_type& __c2) _GLIBCXX_NOEXCEPT
+      { __c1 = __c2; }
+
+      static _GLIBCXX_CONSTEXPR bool
+      eq(const char_type& __c1, const char_type& __c2) _GLIBCXX_NOEXCEPT
+      { return __c1 == __c2; }
+
+      static _GLIBCXX_CONSTEXPR bool
+      lt(const char_type& __c1, const char_type& __c2) _GLIBCXX_NOEXCEPT
+      { return __c1 < __c2; }
+
+      static _GLIBCXX17_CONSTEXPR int
+      compare(const char_type* __s1, const char_type* __s2, size_t __n)
+      {
+#if __cplusplus > 201402
+	if (__builtin_constant_p(__n)
+	    && __constant_char_array_p(__s1, __n)
+	    && __constant_char_array_p(__s2, __n))
+	  return __gnu_cxx::char_traits<char_type>::compare(__s1, __s2, __n);
+#endif
+	if (__n == 0)
+	  return 0;
+	return __builtin_memcmp(__s1, __s2, __n);
+      }
+
+      static _GLIBCXX17_CONSTEXPR size_t
+      length(const char_type* __s)
+      {
+#if __cplusplus > 201402
+	if (__constant_string_p(__s))
+	  return __gnu_cxx::char_traits<char_type>::length(__s);
+#endif
+	size_t __i = 0;
+	while (!eq(__s[__i], char_type()))
+	  ++__i;
+	return __i;
+      }
+
+      static _GLIBCXX17_CONSTEXPR const char_type*
+      find(const char_type* __s, size_t __n, const char_type& __a)
+      {
+#if __cplusplus > 201402
+	if (__builtin_constant_p(__n)
+	    && __builtin_constant_p(__a)
+	    && __constant_char_array_p(__s, __n))
+	  return __gnu_cxx::char_traits<char_type>::find(__s, __n, __a);
+#endif
+	if (__n == 0)
+	  return 0;
+	return static_cast<const char_type*>(__builtin_memchr(__s, __a, __n));
+      }
+
+      static char_type*
+      move(char_type* __s1, const char_type* __s2, size_t __n)
+      {
+	if (__n == 0)
+	  return __s1;
+	return static_cast<char_type*>(__builtin_memmove(__s1, __s2, __n));
+      }
+
+      static char_type*
+      copy(char_type* __s1, const char_type* __s2, size_t __n)
+      {
+	if (__n == 0)
+	  return __s1;
+	return static_cast<char_type*>(__builtin_memcpy(__s1, __s2, __n));
+      }
+
+      static char_type*
+      assign(char_type* __s, size_t __n, char_type __a)
+      {
+	if (__n == 0)
+	  return __s;
+	return static_cast<char_type*>(__builtin_memset(__s, __a, __n));
+      }
+
+      static _GLIBCXX_CONSTEXPR char_type
+      to_char_type(const int_type& __c) _GLIBCXX_NOEXCEPT
+      { return char_type(__c); }
+
+      static _GLIBCXX_CONSTEXPR int_type
+      to_int_type(const char_type& __c) _GLIBCXX_NOEXCEPT
+      { return int_type(__c); }
+
+      static _GLIBCXX_CONSTEXPR bool
+      eq_int_type(const int_type& __c1, const int_type& __c2) _GLIBCXX_NOEXCEPT
+      { return __c1 == __c2; }
+
+      static _GLIBCXX_CONSTEXPR int_type
+      eof() _GLIBCXX_NOEXCEPT
+      { return static_cast<int_type>(-1); }
+
+      static _GLIBCXX_CONSTEXPR int_type
+      not_eof(const int_type& __c) _GLIBCXX_NOEXCEPT
+      { return eq_int_type(__c, eof()) ? 0 : __c; }
+    };
+#endif //_GLIBCXX_USE_CHAR8_T
+
 _GLIBCXX_END_NAMESPACE_VERSION
 } // namespace
 
diff --git a/libstdc++-v3/include/bits/codecvt.h b/libstdc++-v3/include/bits/codecvt.h
index be54a7b71a9..80ec608f2dd 100644
--- a/libstdc++-v3/include/bits/codecvt.h
+++ b/libstdc++-v3/include/bits/codecvt.h
@@ -573,6 +573,122 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       do_max_length() const throw();
     };
 
+#ifdef _GLIBCXX_USE_CHAR8_T
+  /** @brief  Class codecvt<char16_t, char8_t, mbstate_t> specialization.
+   *
+   *  Converts between UTF-16 and UTF-8.
+   */
+  template<>
+    class codecvt<char16_t, char8_t, mbstate_t>
+    : public __codecvt_abstract_base<char16_t, char8_t, mbstate_t>
+    {
+    public:
+      // Types:
+      typedef char16_t			intern_type;
+      typedef char8_t			extern_type;
+      typedef mbstate_t			state_type;
+
+    public:
+      static locale::id			id;
+
+      explicit
+      codecvt(size_t __refs = 0)
+      : __codecvt_abstract_base<char16_t, char8_t, mbstate_t>(__refs) { }
+
+    protected:
+      virtual
+      ~codecvt();
+
+      virtual result
+      do_out(state_type& __state, const intern_type* __from,
+	     const intern_type* __from_end, const intern_type*& __from_next,
+	     extern_type* __to, extern_type* __to_end,
+	     extern_type*& __to_next) const;
+
+      virtual result
+      do_unshift(state_type& __state,
+		 extern_type* __to, extern_type* __to_end,
+		 extern_type*& __to_next) const;
+
+      virtual result
+      do_in(state_type& __state,
+	     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;
+
+      virtual
+      int do_encoding() const throw();
+
+      virtual
+      bool do_always_noconv() const throw();
+
+      virtual
+      int do_length(state_type&, const extern_type* __from,
+		    const extern_type* __end, size_t __max) const;
+
+      virtual int
+      do_max_length() const throw();
+    };
+
+  /** @brief  Class codecvt<char32_t, char8_t, mbstate_t> specialization.
+   *
+   *  Converts between UTF-32 and UTF-8.
+   */
+  template<>
+    class codecvt<char32_t, char8_t, mbstate_t>
+    : public __codecvt_abstract_base<char32_t, char8_t, mbstate_t>
+    {
+    public:
+      // Types:
+      typedef char32_t			intern_type;
+      typedef char8_t			extern_type;
+      typedef mbstate_t			state_type;
+
+    public:
+      static locale::id			id;
+
+      explicit
+      codecvt(size_t __refs = 0)
+      : __codecvt_abstract_base<char32_t, char8_t, mbstate_t>(__refs) { }
+
+    protected:
+      virtual
+      ~codecvt();
+
+      virtual result
+      do_out(state_type& __state, const intern_type* __from,
+	     const intern_type* __from_end, const intern_type*& __from_next,
+	     extern_type* __to, extern_type* __to_end,
+	     extern_type*& __to_next) const;
+
+      virtual result
+      do_unshift(state_type& __state,
+		 extern_type* __to, extern_type* __to_end,
+		 extern_type*& __to_next) const;
+
+      virtual result
+      do_in(state_type& __state,
+	     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;
+
+      virtual
+      int do_encoding() const throw();
+
+      virtual
+      bool do_always_noconv() const throw();
+
+      virtual
+      int do_length(state_type&, const extern_type* __from,
+		    const extern_type* __end, size_t __max) const;
+
+      virtual int
+      do_max_length() const throw();
+    };
+#endif // _GLIBCXX_USE_CHAR8_T
+
 #endif // C++11
 
   /// class codecvt_byname [22.2.1.6].
@@ -639,6 +755,45 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       virtual
       ~codecvt_byname() { }
     };
+
+#if defined(_GLIBCXX_USE_CHAR8_T)
+  template<>
+    class codecvt_byname<char16_t, char8_t, mbstate_t>
+    : public codecvt<char16_t, char8_t, mbstate_t>
+    {
+    public:
+      explicit
+      codecvt_byname(const char* __s, size_t __refs = 0)
+      : codecvt<char16_t, char8_t, mbstate_t>(__refs) { }
+
+      explicit
+      codecvt_byname(const string& __s, size_t __refs = 0)
+      : codecvt_byname(__s.c_str(), __refs) { }
+
+    protected:
+      virtual
+      ~codecvt_byname() { }
+    };
+
+  template<>
+    class codecvt_byname<char32_t, char8_t, mbstate_t>
+    : public codecvt<char32_t, char8_t, mbstate_t>
+    {
+    public:
+      explicit
+      codecvt_byname(const char* __s, size_t __refs = 0)
+      : codecvt<char32_t, char8_t, mbstate_t>(__refs) { }
+
+      explicit
+      codecvt_byname(const string& __s, size_t __refs = 0)
+      : codecvt_byname(__s.c_str(), __refs) { }
+
+    protected:
+      virtual
+      ~codecvt_byname() { }
+    };
+#endif
+
 #endif // C++11
 
   // Inhibit implicit instantiations for required instantiations,
@@ -669,6 +824,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #if __cplusplus >= 201103L
   extern template class codecvt_byname<char16_t, char, mbstate_t>;
   extern template class codecvt_byname<char32_t, char, mbstate_t>;
+
+#if defined(_GLIBCXX_USE_CHAR8_T)
+  extern template class codecvt_byname<char16_t, char8_t, mbstate_t>;
+  extern template class codecvt_byname<char32_t, char8_t, mbstate_t>;
+#endif
+
 #endif
 
 #endif
diff --git a/libstdc++-v3/include/bits/cpp_type_traits.h b/libstdc++-v3/include/bits/cpp_type_traits.h
index 0958c7e7b3a..d7f8517a6ba 100644
--- a/libstdc++-v3/include/bits/cpp_type_traits.h
+++ b/libstdc++-v3/include/bits/cpp_type_traits.h
@@ -48,7 +48,7 @@
 // so function return values won't work:  We need compile-time entities.
 // We're left with types and constant  integral expressions.
 // Secondly, from the point of view of ease of use, type-based compile-time
-// information is -not- *that* convenient.  On has to write lots of
+// information is -not- *that* convenient.  One has to write lots of
 // overloaded functions and to hope that the compiler will select the right
 // one. As a net effect, the overall structure isn't very clear at first
 // glance.
@@ -171,6 +171,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     };
 # endif
 
+#ifdef _GLIBCXX_USE_CHAR8_T
+  template<>
+    struct __is_integer<char8_t>
+    {
+      enum { __value = 1 };
+      typedef __true_type __type;
+    };
+#endif
+
 #if __cplusplus >= 201103L
   template<>
     struct __is_integer<char16_t>
diff --git a/libstdc++-v3/include/bits/fs_path.h b/libstdc++-v3/include/bits/fs_path.h
index 98b8dc08a6e..077045e6c78 100644
--- a/libstdc++-v3/include/bits/fs_path.h
+++ b/libstdc++-v3/include/bits/fs_path.h
@@ -69,8 +69,13 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
   {
     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>>;
+	= __or_<is_same<_Ch, char>,
+#ifdef _GLIBCXX_USE_CHAR8_T
+		is_same<_Ch, char8_t>,
+#endif
+		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>>
@@ -320,7 +325,12 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
 #if _GLIBCXX_USE_WCHAR_T
     std::wstring   wstring() const;
 #endif
+#ifdef _GLIBCXX_USE_CHAR8_T
+    __attribute__((__abi_tag__("__u8")))
+    std::u8string  u8string() const;
+#else
     std::string    u8string() const;
+#endif // _GLIBCXX_USE_CHAR8_T
     std::u16string u16string() const;
     std::u32string u32string() const;
 
@@ -334,7 +344,12 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
 #if _GLIBCXX_USE_WCHAR_T
     std::wstring   generic_wstring() const;
 #endif
+#ifdef _GLIBCXX_USE_CHAR8_T
+    __attribute__((__abi_tag__("__u8")))
+    std::u8string  generic_u8string() const;
+#else
     std::string    generic_u8string() const;
+#endif // _GLIBCXX_USE_CHAR8_T
     std::u16string generic_u16string() const;
     std::u32string generic_u32string() const;
 
@@ -735,10 +750,22 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
       static string_type
       _S_convert(const _CharT* __f, const _CharT* __l)
       {
-	std::codecvt_utf8<_CharT> __cvt;
-	std::string __str;
-	if (__str_codecvt_out(__f, __l, __str, __cvt))
-	  return __str;
+#ifdef _GLIBCXX_USE_CHAR8_T
+	if constexpr (is_same_v<_CharT, char8_t>)
+	  {
+	    string_type __str(__f, __l);
+	    return __str;
+	  }
+	else
+	  {
+#endif
+	    std::codecvt_utf8<_CharT> __cvt;
+	    std::string __str;
+	    if (__str_codecvt_out(__f, __l, __str, __cvt))
+	      return __str;
+#ifdef _GLIBCXX_USE_CHAR8_T
+	  }
+#endif
 	_GLIBCXX_THROW_OR_ABORT(filesystem_error(
 	      "Cannot convert character sequence",
 	      std::make_error_code(errc::illegal_byte_sequence)));
@@ -938,6 +965,15 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
 	{
 	  if constexpr (is_same_v<_CharT, char>)
 	    return __u8str;
+#ifdef _GLIBCXX_USE_CHAR8_T
+	  else if constexpr (is_same_v<_CharT, char8_t>)
+	    {
+	      const char* __f = __u8str.data();
+	      const char* __l = __f + __u8str.size();
+	      _WString __wstr(__f, __l);
+	      return __wstr;
+	    }
+#endif
 	  else
 	    {
 	      _WString __wstr;
@@ -950,10 +986,22 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
 	    }
 	}
 #else
-      codecvt_utf8<_CharT> __cvt;
-      basic_string<_CharT, _Traits, _Allocator> __wstr{__a};
-      if (__str_codecvt_in(__first, __last, __wstr, __cvt))
-	return __wstr;
+#ifdef _GLIBCXX_USE_CHAR8_T
+      if constexpr (is_same_v<_CharT, char8_t>)
+	{
+	  basic_string<_CharT, _Traits, _Allocator> __wstr{__first, __last, __a};
+	  return __wstr;
+	}
+      else
+	{
+#endif
+	  codecvt_utf8<_CharT> __cvt;
+	  basic_string<_CharT, _Traits, _Allocator> __wstr{__a};
+	  if (__str_codecvt_in(__first, __last, __wstr, __cvt))
+	    return __wstr;
+#ifdef _GLIBCXX_USE_CHAR8_T
+	}
+#endif
 #endif
       _GLIBCXX_THROW_OR_ABORT(filesystem_error(
 	    "Cannot convert character sequence",
@@ -978,6 +1026,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
   path::wstring() const { return string<wchar_t>(); }
 #endif
 
+#ifdef _GLIBCXX_USE_CHAR8_T
+  inline std::u8string
+  path::u8string() const { return string<char8_t>(); }
+#else
   inline std::string
   path::u8string() const
   {
@@ -996,6 +1048,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
     return _M_pathname;
 #endif
   }
+#endif // _GLIBCXX_USE_CHAR8_T
 
   inline std::u16string
   path::u16string() const { return string<char16_t>(); }
@@ -1045,9 +1098,15 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
   { return generic_string<wchar_t>(); }
 #endif
 
+#ifdef _GLIBCXX_USE_CHAR8_T
+  inline std::u8string
+  path::generic_u8string() const
+  { return generic_string<char8_t>(); }
+#else
   inline std::string
   path::generic_u8string() const
   { return generic_string(); }
+#endif
 
   inline std::u16string
   path::generic_u16string() const
diff --git a/libstdc++-v3/include/bits/functional_hash.h b/libstdc++-v3/include/bits/functional_hash.h
index 32dc00c5a6f..6a27beed754 100644
--- a/libstdc++-v3/include/bits/functional_hash.h
+++ b/libstdc++-v3/include/bits/functional_hash.h
@@ -135,6 +135,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   /// Explicit specialization for wchar_t.
   _Cxx_hashtable_define_trivial_hash(wchar_t)
 
+#ifdef _GLIBCXX_USE_CHAR8_T
+  /// Explicit specialization for char8_t.
+  _Cxx_hashtable_define_trivial_hash(char8_t)
+#endif
+
   /// Explicit specialization for char16_t.
   _Cxx_hashtable_define_trivial_hash(char16_t)
 
diff --git a/libstdc++-v3/include/bits/locale_conv.h b/libstdc++-v3/include/bits/locale_conv.h
index 8438fedb516..d7510dff80e 100644
--- a/libstdc++-v3/include/bits/locale_conv.h
+++ b/libstdc++-v3/include/bits/locale_conv.h
@@ -158,6 +158,39 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       return __str_codecvt_out(__first, __last, __outstr, __cvt, __state, __n);
     }
 
+#ifdef _GLIBCXX_USE_CHAR8_T
+
+  // Convert wide character string to narrow.
+  template<typename _CharT, typename _Traits, typename _Alloc, typename _State>
+    inline bool
+    __str_codecvt_out(const _CharT* __first, const _CharT* __last,
+		      basic_string<char8_t, _Traits, _Alloc>& __outstr,
+		      const codecvt<_CharT, char8_t, _State>& __cvt,
+		      _State& __state, size_t& __count)
+    {
+      using _Codecvt = codecvt<_CharT, char8_t, _State>;
+      using _ConvFn
+	= codecvt_base::result
+	  (_Codecvt::*)(_State&, const _CharT*, const _CharT*, const _CharT*&,
+			char8_t*, char8_t*, char8_t*&) const;
+      _ConvFn __fn = &codecvt<_CharT, char8_t, _State>::out;
+      return __do_str_codecvt(__first, __last, __outstr, __cvt, __state,
+			      __count, __fn);
+    }
+
+  template<typename _CharT, typename _Traits, typename _Alloc, typename _State>
+    inline bool
+    __str_codecvt_out(const _CharT* __first, const _CharT* __last,
+		      basic_string<char8_t, _Traits, _Alloc>& __outstr,
+		      const codecvt<_CharT, char8_t, _State>& __cvt)
+    {
+      _State __state = {};
+      size_t __n;
+      return __str_codecvt_out(__first, __last, __outstr, __cvt, __state, __n);
+    }
+
+#endif  // _GLIBCXX_USE_CHAR8_T
+
 #ifdef _GLIBCXX_USE_WCHAR_T
 
 _GLIBCXX_BEGIN_NAMESPACE_CXX11
diff --git a/libstdc++-v3/include/bits/locale_facets.h b/libstdc++-v3/include/bits/locale_facets.h
index 66ac9c07a5d..0db24d53e83 100644
--- a/libstdc++-v3/include/bits/locale_facets.h
+++ b/libstdc++-v3/include/bits/locale_facets.h
@@ -59,7 +59,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 # define  _GLIBCXX_NUM_FACETS 14
 # define  _GLIBCXX_NUM_CXX11_FACETS 8
 #endif
-#define _GLIBCXX_NUM_UNICODE_FACETS 2
+#ifdef _GLIBCXX_USE_CHAR8_T
+# define _GLIBCXX_NUM_UNICODE_FACETS 4
+#else
+# define _GLIBCXX_NUM_UNICODE_FACETS 2
+#endif
 
   // Convert string to numeric value of type _Tp and store results.
   // NB: This is specialized for all required types, there is no
diff --git a/libstdc++-v3/include/bits/localefwd.h b/libstdc++-v3/include/bits/localefwd.h
index a8ba24a9661..20a6f006c67 100644
--- a/libstdc++-v3/include/bits/localefwd.h
+++ b/libstdc++-v3/include/bits/localefwd.h
@@ -139,6 +139,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<> class codecvt<char, char, mbstate_t>;
 #ifdef _GLIBCXX_USE_WCHAR_T
   template<> class codecvt<wchar_t, char, mbstate_t>;
+#endif
+#if __cplusplus >= 201103L
+  template<> class codecvt<char16_t, char, mbstate_t>;
+  template<> class codecvt<char32_t, char, mbstate_t>;
+#ifdef _GLIBCXX_USE_CHAR8_T
+  template<> class codecvt<char16_t, char8_t, mbstate_t>;
+  template<> class codecvt<char32_t, char8_t, mbstate_t>;
+#endif
 #endif
   template<typename _InternT, typename _ExternT, typename _StateT>
     class codecvt_byname;
diff --git a/libstdc++-v3/include/bits/postypes.h b/libstdc++-v3/include/bits/postypes.h
index 6d4c35190f4..17f7d63d829 100644
--- a/libstdc++-v3/include/bits/postypes.h
+++ b/libstdc++-v3/include/bits/postypes.h
@@ -235,6 +235,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   /// File position for wchar_t streams.
   typedef fpos<mbstate_t> wstreampos;
 
+#ifdef _GLIBCXX_USE_CHAR8_T
+  /// File position for char8_t streams.
+  typedef fpos<mbstate_t> u8streampos;
+#endif
+
 #if __cplusplus >= 201103L
   /// File position for char16_t streams.
   typedef fpos<mbstate_t> u16streampos;
diff --git a/libstdc++-v3/include/bits/stringfwd.h b/libstdc++-v3/include/bits/stringfwd.h
index 9437b61fc5f..0ced16039a4 100644
--- a/libstdc++-v3/include/bits/stringfwd.h
+++ b/libstdc++-v3/include/bits/stringfwd.h
@@ -58,6 +58,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<> struct char_traits<wchar_t>;
 #endif
 
+#ifdef _GLIBCXX_USE_CHAR8_T
+  template<> struct char_traits<char8_t>;
+#endif
+
 #if __cplusplus >= 201103L
   template<> struct char_traits<char16_t>;
   template<> struct char_traits<char32_t>;
@@ -79,6 +83,11 @@ _GLIBCXX_END_NAMESPACE_CXX11
   typedef basic_string<wchar_t> wstring;   
 #endif
 
+#ifdef _GLIBCXX_USE_CHAR8_T
+  /// A string of @c char8_t
+  typedef basic_string<char8_t> u8string;
+#endif
+
 #if __cplusplus >= 201103L
   /// A string of @c char16_t
   typedef basic_string<char16_t> u16string; 
diff --git a/libstdc++-v3/include/c_global/cstddef b/libstdc++-v3/include/c_global/cstddef
index 4c40737ea63..8c779ec354d 100644
--- a/libstdc++-v3/include/c_global/cstddef
+++ b/libstdc++-v3/include/c_global/cstddef
@@ -75,6 +75,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<> struct __byte_operand<unsigned char> { using __type = byte; };
 #ifdef _GLIBCXX_USE_WCHAR_T
   template<> struct __byte_operand<wchar_t> { using __type = byte; };
+#endif
+#ifdef _GLIBCXX_USE_CHAR8_T
+  template<> struct __byte_operand<char8_t> { using __type = byte; };
 #endif
   template<> struct __byte_operand<char16_t> { using __type = byte; };
   template<> struct __byte_operand<char32_t> { using __type = byte; };
diff --git a/libstdc++-v3/include/experimental/bits/fs_path.h b/libstdc++-v3/include/experimental/bits/fs_path.h
index 239776df313..ebd5072fc1a 100644
--- a/libstdc++-v3/include/experimental/bits/fs_path.h
+++ b/libstdc++-v3/include/experimental/bits/fs_path.h
@@ -82,8 +82,13 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
     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>>;
+	= __or_<is_same<_Ch, char>,
+		is_same<_Ch, wchar_t>,
+#ifdef _GLIBCXX_USE_CHAR8_T
+		is_same<_Ch, char8_t>,
+#endif
+		is_same<_Ch, char16_t>,
+		is_same<_Ch, char32_t>>;
 
     template<typename _Iter,
 	     typename _Iter_traits = std::iterator_traits<_Iter>>
@@ -325,7 +330,12 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
 #if _GLIBCXX_USE_WCHAR_T
     std::wstring   wstring() const;
 #endif
+#ifdef _GLIBCXX_USE_CHAR8_T
+    __attribute__((__abi_tag__("__u8")))
+    std::u8string  u8string() const;
+#else
     std::string    u8string() const;
+#endif // _GLIBCXX_USE_CHAR8_T
     std::u16string u16string() const;
     std::u32string u32string() const;
 
@@ -339,7 +349,12 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
 #if _GLIBCXX_USE_WCHAR_T
     std::wstring   generic_wstring() const;
 #endif
+#ifdef _GLIBCXX_USE_CHAR8_T
+    __attribute__((__abi_tag__("__u8")))
+    std::u8string  generic_u8string() const;
+#else
     std::string    generic_u8string() const;
+#endif // _GLIBCXX_USE_CHAR8_T
     std::u16string generic_u16string() const;
     std::u32string generic_u32string() const;
 
@@ -674,10 +689,22 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
       static string_type
       _S_convert(const _CharT* __f, const _CharT* __l)
       {
-	std::codecvt_utf8<_CharT> __cvt;
-	std::string __str;
-	if (__str_codecvt_out(__f, __l, __str, __cvt))
-	  return __str;
+#ifdef _GLIBCXX_USE_CHAR8_T
+	if constexpr (is_same<_CharT, char8_t>::value)
+	  {
+	    string_type __str(__f, __l);
+	    return __str;
+	  }
+	else
+	  {
+#endif
+	    std::codecvt_utf8<_CharT> __cvt;
+	    std::string __str;
+	    if (__str_codecvt_out(__f, __l, __str, __cvt))
+	      return __str;
+#ifdef _GLIBCXX_USE_CHAR8_T
+	  }
+#endif
 	_GLIBCXX_THROW_OR_ABORT(filesystem_error(
 	      "Cannot convert character sequence",
 	      std::make_error_code(errc::illegal_byte_sequence)));
@@ -867,12 +894,24 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
 	    _WString*
 	    operator()(const _String& __from, _WString& __to, false_type)
 	    {
-	      // use codecvt_utf8<_CharT> to convert UTF-8 to wide string
-	      codecvt_utf8<_CharT> __cvt;
-	      const char* __f = __from.data();
-	      const char* __l = __f + __from.size();
-	      if (__str_codecvt_in(__f, __l, __to, __cvt))
-		return std::__addressof(__to);
+#ifdef _GLIBCXX_USE_CHAR8_T
+	      if constexpr (is_same<_CharT, char8_t>::value)
+	        {
+	          __to.assign(__from.begin(), __from.end());
+	          return std::__addressof(__to);
+	        }
+	      else
+	        {
+#endif
+	          // use codecvt_utf8<_CharT> to convert UTF-8 to wide string
+	          codecvt_utf8<_CharT> __cvt;
+	          const char* __f = __from.data();
+	          const char* __l = __f + __from.size();
+	          if (__str_codecvt_in(__f, __l, __to, __cvt))
+		    return std::__addressof(__to);
+#ifdef _GLIBCXX_USE_CHAR8_T
+	        }
+#endif
 	      return nullptr;
 	    }
 	  } __dispatch;
@@ -881,10 +920,22 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
 	    return *__p;
 	}
 #else
-      codecvt_utf8<_CharT> __cvt;
-      basic_string<_CharT, _Traits, _Allocator> __wstr{__a};
-      if (__str_codecvt_in(__first, __last, __wstr, __cvt))
-	return __wstr;
+#ifdef _GLIBCXX_USE_CHAR8_T
+      if constexpr (is_same<_CharT, char8_t>::value)
+        {
+          basic_string<_CharT, _Traits, _Allocator> __wstr{__first, __last, __a};
+          return __wstr;
+        }
+      else
+        {
+#endif
+          codecvt_utf8<_CharT> __cvt;
+          basic_string<_CharT, _Traits, _Allocator> __wstr{__a};
+          if (__str_codecvt_in(__first, __last, __wstr, __cvt))
+	    return __wstr;
+#ifdef _GLIBCXX_USE_CHAR8_T
+        }
+#endif
 #endif
       _GLIBCXX_THROW_OR_ABORT(filesystem_error(
 	    "Cannot convert character sequence",
@@ -899,6 +950,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
   path::wstring() const { return string<wchar_t>(); }
 #endif
 
+#ifdef _GLIBCXX_USE_CHAR8_T
+  inline std::u8string
+  path::u8string() const { return string<char8_t>(); }
+#else
   inline std::string
   path::u8string() const
   {
@@ -917,6 +972,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
     return _M_pathname;
 #endif
   }
+#endif // _GLIBCXX_USE_CHAR8_T
 
   inline std::u16string
   path::u16string() const { return string<char16_t>(); }
@@ -938,8 +994,13 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
   path::generic_wstring() const { return wstring(); }
 #endif
 
+#ifdef _GLIBCXX_USE_CHAR8_T
+  inline std::u8string
+  path::generic_u8string() const { return u8string(); }
+#else
   inline std::string
   path::generic_u8string() const { return u8string(); }
+#endif
 
   inline std::u16string
   path::generic_u16string() const { return u16string(); }
diff --git a/libstdc++-v3/include/experimental/string b/libstdc++-v3/include/experimental/string
index a8ab002d445..65bf2b8d009 100644
--- a/libstdc++-v3/include/experimental/string
+++ b/libstdc++-v3/include/experimental/string
@@ -73,6 +73,9 @@ inline namespace fundamentals_v2
     // basic_string typedef names using polymorphic allocator in namespace
     // std::experimental::pmr
     typedef basic_string<char> string;
+#ifdef _GLIBCXX_USE_CHAR8_T
+    typedef basic_string<char8_t> u8string;
+#endif
     typedef basic_string<char16_t> u16string;
     typedef basic_string<char32_t> u32string;
     typedef basic_string<wchar_t> wstring;
diff --git a/libstdc++-v3/include/experimental/string_view b/libstdc++-v3/include/experimental/string_view
index 8cc0e90246b..ce2c14cfe36 100644
--- a/libstdc++-v3/include/experimental/string_view
+++ b/libstdc++-v3/include/experimental/string_view
@@ -565,6 +565,9 @@ inline namespace fundamentals_v1
   using string_view = basic_string_view<char>;
 #ifdef _GLIBCXX_USE_WCHAR_T
   using wstring_view = basic_string_view<wchar_t>;
+#endif
+#ifdef _GLIBCXX_USE_CHAR8_T
+  using u8string_view = basic_string_view<char8_t>;
 #endif
   using u16string_view = basic_string_view<char16_t>;
   using u32string_view = basic_string_view<char32_t>;
@@ -605,6 +608,21 @@ inline namespace fundamentals_v1
     { };
 #endif
 
+#ifdef _GLIBCXX_USE_CHAR8_T
+  template<>
+    struct hash<experimental::u8string_view>
+    : public __hash_base<size_t, experimental::u8string_view>
+    {
+      size_t
+      operator()(const experimental::u8string_view& __s) const noexcept
+      { return std::_Hash_impl::hash(__s.data(), __s.length()); }
+    };
+
+  template<>
+    struct __is_fast_hash<hash<experimental::u8string_view>> : std::false_type
+    { };
+#endif
+
   template<>
     struct hash<experimental::u16string_view>
     : public __hash_base<size_t, experimental::u16string_view>
@@ -652,6 +670,12 @@ namespace experimental
     { return basic_string_view<wchar_t>{__str, __len}; }
 #endif
 
+#ifdef _GLIBCXX_USE_CHAR8_T
+    inline constexpr basic_string_view<char8_t>
+    operator""sv(const char8_t* __str, size_t __len) noexcept
+    { return basic_string_view<char8_t>{__str, __len}; }
+#endif
+
     inline constexpr basic_string_view<char16_t>
     operator""sv(const char16_t* __str, size_t __len) noexcept
     { return basic_string_view<char16_t>{__str, __len}; }
diff --git a/libstdc++-v3/include/std/atomic b/libstdc++-v3/include/std/atomic
index 32179613d6b..7acc2462bfb 100644
--- a/libstdc++-v3/include/std/atomic
+++ b/libstdc++-v3/include/std/atomic
@@ -904,6 +904,31 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #endif
     };
 
+#ifdef _GLIBCXX_USE_CHAR8_T
+  /// Explicit specialization for char8_t.
+  template<>
+    struct atomic<char8_t> : __atomic_base<char8_t>
+    {
+      typedef char8_t 			__integral_type;
+      typedef __atomic_base<char8_t> 	__base_type;
+
+      atomic() noexcept = default;
+      ~atomic() noexcept = default;
+      atomic(const atomic&) = delete;
+      atomic& operator=(const atomic&) = delete;
+      atomic& operator=(const atomic&) volatile = delete;
+
+      constexpr atomic(__integral_type __i) noexcept : __base_type(__i) { }
+
+      using __base_type::operator __integral_type;
+      using __base_type::operator=;
+
+#if __cplusplus > 201402L
+    static constexpr bool is_always_lock_free = ATOMIC_CHAR8_T_LOCK_FREE == 2;
+#endif
+    };
+#endif
+
   /// Explicit specialization for char16_t.
   template<>
     struct atomic<char16_t> : __atomic_base<char16_t>
@@ -990,6 +1015,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   /// atomic_wchar_t
   typedef atomic<wchar_t>		atomic_wchar_t;
 
+#ifdef _GLIBCXX_USE_CHAR8_T
+  /// atomic_char8_t
+  typedef atomic<char8_t>		atomic_char8_t;
+#endif
+
   /// atomic_char16_t
   typedef atomic<char16_t>		atomic_char16_t;
 
diff --git a/libstdc++-v3/include/std/charconv b/libstdc++-v3/include/std/charconv
index 3363247e11e..9f01d4c0889 100644
--- a/libstdc++-v3/include/std/charconv
+++ b/libstdc++-v3/include/std/charconv
@@ -66,6 +66,9 @@ namespace __detail
 	  __not_<__is_one_of<_Tp, bool, char16_t, char32_t
 #if _GLIBCXX_USE_WCHAR_T
 	  , wchar_t
+#endif
+#if _GLIBCXX_USE_CHAR8_T
+	  , char8_t
 #endif
 	    >>>;
 
diff --git a/libstdc++-v3/include/std/limits b/libstdc++-v3/include/std/limits
index 759c49568dd..dbea152d014 100644
--- a/libstdc++-v3/include/std/limits
+++ b/libstdc++-v3/include/std/limits
@@ -374,6 +374,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   // Now there follow 16 explicit specializations.  Yes, 16.  Make sure
   // you get the count right. (18 in C++11 mode, with char16_t and char32_t.)
+  // (+1 if char8_t is enabled.)
 
   // _GLIBCXX_RESOLVE_LIB_DEFECTS
   // 184. numeric_limits<bool> wording problems
@@ -725,6 +726,71 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        = round_toward_zero;
     };
 
+#if _GLIBCXX_USE_CHAR8_T
+  /// numeric_limits<char8_t> specialization.
+  template<>
+    struct numeric_limits<char8_t>
+    {
+      static _GLIBCXX_USE_CONSTEXPR bool is_specialized = true;
+
+      static _GLIBCXX_CONSTEXPR char8_t
+      min() _GLIBCXX_USE_NOEXCEPT { return __glibcxx_min (char8_t); }
+
+      static _GLIBCXX_CONSTEXPR char8_t
+      max() _GLIBCXX_USE_NOEXCEPT { return __glibcxx_max (char8_t); }
+
+      static _GLIBCXX_CONSTEXPR char8_t
+      lowest() _GLIBCXX_USE_NOEXCEPT { return min(); }
+
+      static _GLIBCXX_USE_CONSTEXPR int digits = __glibcxx_digits (char8_t);
+      static _GLIBCXX_USE_CONSTEXPR int digits10 = __glibcxx_digits10 (char8_t);
+      static _GLIBCXX_USE_CONSTEXPR int max_digits10 = 0;
+      static _GLIBCXX_USE_CONSTEXPR bool is_signed = __glibcxx_signed (char8_t);
+      static _GLIBCXX_USE_CONSTEXPR bool is_integer = true;
+      static _GLIBCXX_USE_CONSTEXPR bool is_exact = true;
+      static _GLIBCXX_USE_CONSTEXPR int radix = 2;
+
+      static _GLIBCXX_CONSTEXPR char8_t
+      epsilon() _GLIBCXX_USE_NOEXCEPT { return 0; }
+
+      static _GLIBCXX_CONSTEXPR char8_t
+      round_error() _GLIBCXX_USE_NOEXCEPT { return 0; }
+
+      static _GLIBCXX_USE_CONSTEXPR int min_exponent = 0;
+      static _GLIBCXX_USE_CONSTEXPR int min_exponent10 = 0;
+      static _GLIBCXX_USE_CONSTEXPR int max_exponent = 0;
+      static _GLIBCXX_USE_CONSTEXPR int max_exponent10 = 0;
+
+      static _GLIBCXX_USE_CONSTEXPR bool has_infinity = false;
+      static _GLIBCXX_USE_CONSTEXPR bool has_quiet_NaN = false;
+      static _GLIBCXX_USE_CONSTEXPR bool has_signaling_NaN = false;
+      static _GLIBCXX_USE_CONSTEXPR float_denorm_style has_denorm
+	= denorm_absent;
+      static _GLIBCXX_USE_CONSTEXPR bool has_denorm_loss = false;
+
+      static _GLIBCXX_CONSTEXPR char8_t
+      infinity() _GLIBCXX_USE_NOEXCEPT { return char8_t(); }
+
+      static _GLIBCXX_CONSTEXPR char8_t
+      quiet_NaN() _GLIBCXX_USE_NOEXCEPT { return char8_t(); }
+
+      static _GLIBCXX_CONSTEXPR char8_t
+      signaling_NaN() _GLIBCXX_USE_NOEXCEPT { return char8_t(); }
+
+      static _GLIBCXX_CONSTEXPR char8_t
+      denorm_min() _GLIBCXX_USE_NOEXCEPT { return char8_t(); }
+
+      static _GLIBCXX_USE_CONSTEXPR bool is_iec559 = false;
+      static _GLIBCXX_USE_CONSTEXPR bool is_bounded = true;
+      static _GLIBCXX_USE_CONSTEXPR bool is_modulo = !is_signed;
+
+      static _GLIBCXX_USE_CONSTEXPR bool traps = __glibcxx_integral_traps;
+      static _GLIBCXX_USE_CONSTEXPR bool tinyness_before = false;
+      static _GLIBCXX_USE_CONSTEXPR float_round_style round_style
+	= round_toward_zero;
+    };
+#endif
+
 #if __cplusplus >= 201103L
   /// numeric_limits<char16_t> specialization.
   template<>
diff --git a/libstdc++-v3/include/std/string b/libstdc++-v3/include/std/string
index caa54c24100..100c6c84ef6 100644
--- a/libstdc++-v3/include/std/string
+++ b/libstdc++-v3/include/std/string
@@ -65,6 +65,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       using basic_string = std::basic_string<_CharT, _Traits,
 					     polymorphic_allocator<_CharT>>;
     using string    = basic_string<char>;
+#ifdef _GLIBCXX_USE_CHAR8_T
+    using u8string  = basic_string<char8_t>;
+#endif
     using u16string = basic_string<char16_t>;
     using u32string = basic_string<char32_t>;
 #ifdef _GLIBCXX_USE_WCHAR_T
diff --git a/libstdc++-v3/include/std/string_view b/libstdc++-v3/include/std/string_view
index a81e0befdd5..844cfb148ad 100644
--- a/libstdc++-v3/include/std/string_view
+++ b/libstdc++-v3/include/std/string_view
@@ -583,7 +583,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #ifdef _GLIBCXX_USE_WCHAR_T
   using wstring_view = basic_string_view<wchar_t>;
 #endif
-
+#ifdef _GLIBCXX_USE_CHAR8_T
+  using u8string_view = basic_string_view<char8_t>;
+#endif
   using u16string_view = basic_string_view<char16_t>;
   using u32string_view = basic_string_view<char32_t>;
 
@@ -621,6 +623,21 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { };
 #endif
 
+#ifdef _GLIBCXX_USE_CHAR8_T
+  template<>
+    struct hash<u8string_view>
+    : public __hash_base<size_t, u8string_view>
+    {
+      size_t
+      operator()(const u8string_view& __str) const noexcept
+      { return std::_Hash_impl::hash(__str.data(), __str.length()); }
+    };
+
+  template<>
+    struct __is_fast_hash<hash<u8string_view>> : std::false_type
+    { };
+#endif
+
   template<>
     struct hash<u16string_view>
     : public __hash_base<size_t, u16string_view>
@@ -665,6 +682,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { return basic_string_view<wchar_t>{__str, __len}; }
 #endif
 
+#ifdef _GLIBCXX_USE_CHAR8_T
+    inline constexpr basic_string_view<char8_t>
+    operator""sv(const char8_t* __str, size_t __len) noexcept
+    { return basic_string_view<char8_t>{__str, __len}; }
+#endif
+
     inline constexpr basic_string_view<char16_t>
     operator""sv(const char16_t* __str, size_t __len) noexcept
     { return basic_string_view<char16_t>{__str, __len}; }
diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index bc2250d9dce..993967244ff 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -234,6 +234,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     : public true_type { };
 #endif
 
+#ifdef _GLIBCXX_USE_CHAR8_T
+  template<>
+    struct __is_integral_helper<char8_t>
+    : public true_type { };
+#endif
+
   template<>
     struct __is_integral_helper<char16_t>
     : public true_type { };
@@ -1680,8 +1686,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	= typename __match_cv_qualifiers<_Tp, __unsigned_type>::__type;
     };
 
-  // wchar_t, char16_t and char32_t are integral types but are neither
-  // signed integer types nor unsigned integer types, so must be
+  // wchar_t, char8_t, char16_t and char32_t are integral types but are
+  // neither signed integer types nor unsigned integer types, so must be
   // transformed to the unsigned integer type with the smallest rank.
   // Use the partial specialization for enumeration types to do that.
 #if defined(_GLIBCXX_USE_WCHAR_T)
@@ -1693,6 +1699,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     };
 #endif
 
+#ifdef _GLIBCXX_USE_CHAR8_T
+  template<>
+    struct __make_unsigned<char8_t>
+    {
+      using __type
+	= typename __make_unsigned_selector<char8_t, false, true>::__type;
+    };
+#endif
+
   template<>
     struct __make_unsigned<char16_t>
     {
@@ -1810,6 +1825,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     };
 #endif
 
+#if defined(_GLIBCXX_USE_CHAR8_T)
+  template<>
+    struct __make_signed<char8_t>
+    {
+      using __type
+	= typename __make_signed_selector<char8_t, false, true>::__type;
+    };
+#endif
+
   template<>
     struct __make_signed<char16_t>
     {
diff --git a/libstdc++-v3/libsupc++/atomic_lockfree_defines.h b/libstdc++-v3/libsupc++/atomic_lockfree_defines.h
index 24d4fe3ddda..614a84c1fa8 100644
--- a/libstdc++-v3/libsupc++/atomic_lockfree_defines.h
+++ b/libstdc++-v3/libsupc++/atomic_lockfree_defines.h
@@ -49,6 +49,9 @@
 #define ATOMIC_BOOL_LOCK_FREE		__GCC_ATOMIC_BOOL_LOCK_FREE
 #define ATOMIC_CHAR_LOCK_FREE		__GCC_ATOMIC_CHAR_LOCK_FREE
 #define ATOMIC_WCHAR_T_LOCK_FREE	__GCC_ATOMIC_WCHAR_T_LOCK_FREE
+#ifdef _GLIBCXX_USE_CHAR8_T
+#define ATOMIC_CHAR8_T_LOCK_FREE	__GCC_ATOMIC_CHAR8_T_LOCK_FREE
+#endif
 #define ATOMIC_CHAR16_T_LOCK_FREE	__GCC_ATOMIC_CHAR16_T_LOCK_FREE
 #define ATOMIC_CHAR32_T_LOCK_FREE	__GCC_ATOMIC_CHAR32_T_LOCK_FREE
 #define ATOMIC_SHORT_LOCK_FREE		__GCC_ATOMIC_SHORT_LOCK_FREE
diff --git a/libstdc++-v3/src/c++11/Makefile.am b/libstdc++-v3/src/c++11/Makefile.am
index 46d31b9cc64..9fc18662702 100644
--- a/libstdc++-v3/src/c++11/Makefile.am
+++ b/libstdc++-v3/src/c++11/Makefile.am
@@ -126,6 +126,16 @@ hashtable_c++0x.lo: hashtable_c++0x.cc
 hashtable_c++0x.o: hashtable_c++0x.cc
 	$(CXXCOMPILE) -fimplicit-templates -c $<
 
+# Use special rules for source files that require -fchar8_t.
+codecvt.lo: codecvt.cc
+	$(LTCXXCOMPILE) -fchar8_t -c $<
+codecvt.o: codecvt.cc
+	$(CXXCOMPILE) -fchar8_t -c $<
+limits.lo: limits.cc
+	$(LTCXXCOMPILE) -fchar8_t -c $<
+limits.o: limits.cc
+	$(CXXCOMPILE) -fchar8_t -c $<
+
 if ENABLE_DUAL_ABI
 # Rewrite the type info for __ios_failure.
 rewrite_ios_failure_typeinfo = sed -e '/^_*_ZTISt13__ios_failure:/,/_ZTVN10__cxxabiv120__si_class_type_infoE/s/_ZTVN10__cxxabiv120__si_class_type_infoE/_ZTVSt19__iosfail_type_info/'
diff --git a/libstdc++-v3/src/c++11/codecvt.cc b/libstdc++-v3/src/c++11/codecvt.cc
index b2fa375cdf5..372aea289b7 100644
--- a/libstdc++-v3/src/c++11/codecvt.cc
+++ b/libstdc++-v3/src/c++11/codecvt.cc
@@ -193,8 +193,9 @@ namespace
     }
 
   // If generate_header is set in mode write out UTF-8 BOM.
+  template<typename C>
   bool
-  write_utf8_bom(range<char>& to, codecvt_mode mode)
+  write_utf8_bom(range<C>& to, codecvt_mode mode)
   {
     if (mode & generate_header)
       return write_bom(to, utf8_bom);
@@ -218,8 +219,9 @@ namespace
   }
 
   // If consume_header is set in mode update from.next to after any BOM.
+  template<typename C>
   void
-  read_utf8_bom(range<const char>& from, codecvt_mode mode)
+  read_utf8_bom(range<const C>& from, codecvt_mode mode)
   {
     if (mode & consume_header)
       read_bom(from, utf8_bom);
@@ -245,8 +247,9 @@ namespace
   // Read a codepoint from a UTF-8 multibyte sequence.
   // Updates from.next if the codepoint is not greater than maxcode.
   // Returns invalid_mb_sequence, incomplete_mb_character or the code point.
+  template<typename C>
   char32_t
-  read_utf8_code_point(range<const char>& from, unsigned long maxcode)
+  read_utf8_code_point(range<const C>& from, unsigned long maxcode)
   {
     const size_t avail = from.size();
     if (avail == 0)
@@ -315,8 +318,9 @@ namespace
       return invalid_mb_sequence;
   }
 
+  template<typename C>
   bool
-  write_utf8_code_point(range<char>& to, char32_t code_point)
+  write_utf8_code_point(range<C>& to, char32_t code_point)
   {
     if (code_point < 0x80)
       {
@@ -445,8 +449,9 @@ namespace
   }
 
   // utf8 -> ucs4
+  template<typename C>
   codecvt_base::result
-  ucs4_in(range<const char>& from, range<char32_t>& to,
+  ucs4_in(range<const C>& from, range<char32_t>& to,
           unsigned long maxcode = max_code_point, codecvt_mode mode = {})
   {
     read_utf8_bom(from, mode);
@@ -463,8 +468,9 @@ namespace
   }
 
   // ucs4 -> utf8
+  template<typename C>
   codecvt_base::result
-  ucs4_out(range<const char32_t>& from, range<char>& to,
+  ucs4_out(range<const char32_t>& from, range<C>& to,
            unsigned long maxcode = max_code_point, codecvt_mode mode = {})
   {
     if (!write_utf8_bom(to, mode))
@@ -522,9 +528,9 @@ namespace
   enum class surrogates { allowed, disallowed };
 
   // utf8 -> utf16 (or utf8 -> ucs2 if s == surrogates::disallowed)
-  template<typename C>
+  template<typename C8, typename C16>
   codecvt_base::result
-  utf16_in(range<const char>& from, range<C>& to,
+  utf16_in(range<const C8>& from, range<C16>& to,
 	   unsigned long maxcode = max_code_point, codecvt_mode mode = {},
 	   surrogates s = surrogates::allowed)
   {
@@ -552,9 +558,9 @@ namespace
   }
 
   // utf16 -> utf8 (or ucs2 -> utf8 if s == surrogates::disallowed)
-  template<typename C>
+  template<typename C16, typename C8>
   codecvt_base::result
-  utf16_out(range<const C>& from, range<char>& to,
+  utf16_out(range<const C16>& from, range<C8>& to,
 	    unsigned long maxcode = max_code_point, codecvt_mode mode = {},
 	    surrogates s = surrogates::allowed)
   {
@@ -593,11 +599,12 @@ namespace
   }
 
   // return pos such that [begin,pos) is valid UTF-16 string no longer than max
-  const char*
-  utf16_span(const char* begin, const char* end, size_t max,
+  template<typename C>
+  const C*
+  utf16_span(const C* begin, const C* end, size_t max,
 	     char32_t maxcode = max_code_point, codecvt_mode mode = {})
   {
-    range<const char> from{ begin, end };
+    range<const C> from{ begin, end };
     read_utf8_bom(from, mode);
     size_t count = 0;
     while (count+1 < max)
@@ -615,8 +622,9 @@ namespace
   }
 
   // utf8 -> ucs2
+  template<typename C>
   codecvt_base::result
-  ucs2_in(range<const char>& from, range<char16_t>& to,
+  ucs2_in(range<const C>& from, range<char16_t>& to,
 	  char32_t maxcode = max_code_point, codecvt_mode mode = {})
   {
     // UCS-2 only supports characters in the BMP, i.e. one UTF-16 code unit:
@@ -625,8 +633,9 @@ namespace
   }
 
   // ucs2 -> utf8
+  template<typename C>
   codecvt_base::result
-  ucs2_out(range<const char16_t>& from, range<char>& to,
+  ucs2_out(range<const char16_t>& from, range<C>& to,
 	   char32_t maxcode = max_code_point, codecvt_mode mode = {})
   {
     // UCS-2 only supports characters in the BMP, i.e. one UTF-16 code unit:
@@ -687,11 +696,12 @@ namespace
     return reinterpret_cast<const char16_t*>(from.next);
   }
 
-  const char*
-  ucs2_span(const char* begin, const char* end, size_t max,
+  template<typename C>
+  const C*
+  ucs2_span(const C* begin, const C* end, size_t max,
             char32_t maxcode, codecvt_mode mode)
   {
-    range<const char> from{ begin, end };
+    range<const C> from{ begin, end };
     read_utf8_bom(from, mode);
     // UCS-2 only supports characters in the BMP, i.e. one UTF-16 code unit:
     maxcode = std::min(max_single_utf16_unit, maxcode);
@@ -702,11 +712,12 @@ namespace
   }
 
   // return pos such that [begin,pos) is valid UCS-4 string no longer than max
-  const char*
-  ucs4_span(const char* begin, const char* end, size_t max,
+  template<typename C>
+  const C*
+  ucs4_span(const C* begin, const C* end, size_t max,
             char32_t maxcode = max_code_point, codecvt_mode mode = {})
   {
-    range<const char> from{ begin, end };
+    range<const C> from{ begin, end };
     read_utf8_bom(from, mode);
     char32_t c = 0;
     while (max-- && c <= maxcode)
@@ -875,6 +886,156 @@ codecvt<char32_t, char, mbstate_t>::do_max_length() const throw()
   return 4;
 }
 
+#if defined(_GLIBCXX_USE_CHAR8_T)
+// Define members of codecvt<char16_t, char8_t, mbstate_t> specialization.
+// Converts from UTF-8 to UTF-16.
+
+locale::id codecvt<char16_t, char8_t, mbstate_t>::id;
+
+codecvt<char16_t, char8_t, mbstate_t>::~codecvt() { }
+
+codecvt_base::result
+codecvt<char16_t, char8_t, mbstate_t>::
+do_out(state_type&,
+       const intern_type* __from,
+       const intern_type* __from_end, const intern_type*& __from_next,
+       extern_type* __to, extern_type* __to_end,
+       extern_type*& __to_next) const
+{
+  range<const char16_t> from{ __from, __from_end };
+  range<char8_t> to{ __to, __to_end };
+  auto res = utf16_out(from, to);
+  __from_next = from.next;
+  __to_next = to.next;
+  return res;
+}
+
+codecvt_base::result
+codecvt<char16_t, char8_t, mbstate_t>::
+do_unshift(state_type&, extern_type* __to, extern_type*,
+	   extern_type*& __to_next) const
+{
+  __to_next = __to;
+  return noconv; // we don't use mbstate_t for the unicode facets
+}
+
+codecvt_base::result
+codecvt<char16_t, char8_t, mbstate_t>::
+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
+{
+  range<const char8_t> from{ __from, __from_end };
+  range<char16_t> to{ __to, __to_end };
+#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+  codecvt_mode mode = {};
+#else
+  codecvt_mode mode = little_endian;
+#endif
+  auto res = utf16_in(from, to, max_code_point, mode);
+  __from_next = from.next;
+  __to_next = to.next;
+  return res;
+}
+
+int
+codecvt<char16_t, char8_t, mbstate_t>::do_encoding() const throw()
+{ return 0; } // UTF-8 is not a fixed-width encoding
+
+bool
+codecvt<char16_t, char8_t, mbstate_t>::do_always_noconv() const throw()
+{ return false; }
+
+int
+codecvt<char16_t, char8_t, mbstate_t>::
+do_length(state_type&, const extern_type* __from,
+	  const extern_type* __end, size_t __max) const
+{
+  __end = utf16_span(__from, __end, __max);
+  return __end - __from;
+}
+
+int
+codecvt<char16_t, char8_t, mbstate_t>::do_max_length() const throw()
+{
+  // A single character (one or two UTF-16 code units) requires
+  // up to four UTF-8 code units.
+  return 4;
+}
+
+// Define members of codecvt<char32_t, char8_t, mbstate_t> specialization.
+// Converts from UTF-8 to UTF-32 (aka UCS-4).
+
+locale::id codecvt<char32_t, char8_t, mbstate_t>::id;
+
+codecvt<char32_t, char8_t, mbstate_t>::~codecvt() { }
+
+codecvt_base::result
+codecvt<char32_t, char8_t, mbstate_t>::
+do_out(state_type&, const intern_type* __from, const intern_type* __from_end,
+       const intern_type*& __from_next,
+       extern_type* __to, extern_type* __to_end,
+       extern_type*& __to_next) const
+{
+  range<const char32_t> from{ __from, __from_end };
+  range<char8_t> to{ __to, __to_end };
+  auto res = ucs4_out(from, to);
+  __from_next = from.next;
+  __to_next = to.next;
+  return res;
+}
+
+codecvt_base::result
+codecvt<char32_t, char8_t, mbstate_t>::
+do_unshift(state_type&, extern_type* __to, extern_type*,
+	   extern_type*& __to_next) const
+{
+  __to_next = __to;
+  return noconv;
+}
+
+codecvt_base::result
+codecvt<char32_t, char8_t, mbstate_t>::
+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
+{
+  range<const char8_t> from{ __from, __from_end };
+  range<char32_t> to{ __to, __to_end };
+  auto res = ucs4_in(from, to);
+  __from_next = from.next;
+  __to_next = to.next;
+  return res;
+}
+
+int
+codecvt<char32_t, char8_t, mbstate_t>::do_encoding() const throw()
+{ return 0; } // UTF-8 is not a fixed-width encoding
+
+bool
+codecvt<char32_t, char8_t, mbstate_t>::do_always_noconv() const throw()
+{ return false; }
+
+int
+codecvt<char32_t, char8_t, mbstate_t>::
+do_length(state_type&, const extern_type* __from,
+	  const extern_type* __end, size_t __max) const
+{
+  __end = ucs4_span(__from, __end, __max);
+  return __end - __from;
+}
+
+int
+codecvt<char32_t, char8_t, mbstate_t>::do_max_length() const throw()
+{
+  // A single character (one UTF-32 code unit) requires
+  // up to 4 UTF-8 code units.
+  return 4;
+}
+#endif // _GLIBCXX_USE_CHAR8_T
+
 // Define members of codecvt_utf8<char16_t> base class implementation.
 // Converts from UTF-8 to UCS-2.
 
@@ -1636,5 +1797,12 @@ inline template class __codecvt_abstract_base<char32_t, char, mbstate_t>;
 template class codecvt_byname<char16_t, char, mbstate_t>;
 template class codecvt_byname<char32_t, char, mbstate_t>;
 
+#if defined(_GLIBCXX_USE_CHAR8_T)
+inline template class __codecvt_abstract_base<char16_t, char8_t, mbstate_t>;
+inline template class __codecvt_abstract_base<char32_t, char8_t, mbstate_t>;
+template class codecvt_byname<char16_t, char8_t, mbstate_t>;
+template class codecvt_byname<char32_t, char8_t, mbstate_t>;
+#endif
+
 _GLIBCXX_END_NAMESPACE_VERSION
 }
diff --git a/libstdc++-v3/src/c++11/limits.cc b/libstdc++-v3/src/c++11/limits.cc
index ed7e631ed88..77b652de42d 100644
--- a/libstdc++-v3/src/c++11/limits.cc
+++ b/libstdc++-v3/src/c++11/limits.cc
@@ -525,6 +525,33 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   const bool numeric_limits<long double>::tinyness_before;
   const float_round_style numeric_limits<long double>::round_style;
 
+#ifdef _GLIBCXX_USE_CHAR8_T
+  // char8_t
+  const bool numeric_limits<char8_t>::is_specialized;
+  const int  numeric_limits<char8_t>::digits;
+  const int  numeric_limits<char8_t>::digits10;
+  const int  numeric_limits<char8_t>::max_digits10;
+  const bool numeric_limits<char8_t>::is_signed;
+  const bool numeric_limits<char8_t>::is_integer;
+  const bool numeric_limits<char8_t>::is_exact;
+  const int  numeric_limits<char8_t>::radix;
+  const int  numeric_limits<char8_t>::min_exponent;
+  const int  numeric_limits<char8_t>::min_exponent10;
+  const int  numeric_limits<char8_t>::max_exponent;
+  const int  numeric_limits<char8_t>::max_exponent10;
+  const bool numeric_limits<char8_t>::has_infinity;
+  const bool numeric_limits<char8_t>::has_quiet_NaN;
+  const bool numeric_limits<char8_t>::has_signaling_NaN;
+  const float_denorm_style numeric_limits<char8_t>::has_denorm;
+  const bool numeric_limits<char8_t>::has_denorm_loss;
+  const bool numeric_limits<char8_t>::is_iec559;
+  const bool numeric_limits<char8_t>::is_bounded;
+  const bool numeric_limits<char8_t>::is_modulo;
+  const bool numeric_limits<char8_t>::traps;
+  const bool numeric_limits<char8_t>::tinyness_before;
+  const float_round_style numeric_limits<char8_t>::round_style;
+#endif // _GLIBCXX_USE_CHAR8_T
+
   // char16_t
   const bool numeric_limits<char16_t>::is_specialized;
   const int  numeric_limits<char16_t>::digits;
diff --git a/libstdc++-v3/src/c++98/Makefile.am b/libstdc++-v3/src/c++98/Makefile.am
index b9f59ecaa10..ba88f002389 100644
--- a/libstdc++-v3/src/c++98/Makefile.am
+++ b/libstdc++-v3/src/c++98/Makefile.am
@@ -184,13 +184,13 @@ endif
 
 # XXX TODO move locale_init.cc and localename.cc to src/c++11
 locale_init.lo: locale_init.cc
-	$(LTCXXCOMPILE) -std=gnu++11 -c $<
+	$(LTCXXCOMPILE) -std=gnu++11 -fchar8_t -c $<
 locale_init.o: locale_init.cc
-	$(LTCXXCOMPILE) -std=gnu++11 -c $<
+	$(LTCXXCOMPILE) -std=gnu++11 -fchar8_t -c $<
 localename.lo: localename.cc
-	$(LTCXXCOMPILE) -std=gnu++11 -c $<
+	$(LTCXXCOMPILE) -std=gnu++11 -fchar8_t -c $<
 localename.o: localename.cc
-	$(LTCXXCOMPILE) -std=gnu++11 -c $<
+	$(LTCXXCOMPILE) -std=gnu++11 -fchar8_t -c $<
 
 # Use special rules for the deprecated source files so that they find
 # deprecated include files.
diff --git a/libstdc++-v3/src/c++98/locale_init.cc b/libstdc++-v3/src/c++98/locale_init.cc
index 0b778de9c40..e5e9d74379f 100644
--- a/libstdc++-v3/src/c++98/locale_init.cc
+++ b/libstdc++-v3/src/c++98/locale_init.cc
@@ -209,6 +209,16 @@ namespace
   __attribute__ ((aligned(__alignof__(codecvt<char32_t, char, mbstate_t>))));
   fake_codecvt_c32 codecvt_c32;
 
+#ifdef _GLIBCXX_USE_CHAR8_T
+  typedef char fake_codecvt_c16_c8[sizeof(codecvt<char16_t, char8_t, mbstate_t>)]
+  __attribute__ ((aligned(__alignof__(codecvt<char16_t, char8_t, mbstate_t>))));
+  fake_codecvt_c16_c8 codecvt_c16_c8;
+
+  typedef char fake_codecvt_c32_c8[sizeof(codecvt<char32_t, char8_t, mbstate_t>)]
+  __attribute__ ((aligned(__alignof__(codecvt<char32_t, char8_t, mbstate_t>))));
+  fake_codecvt_c32_c8 codecvt_c32_c8;
+#endif
+
   // Storage for "C" locale caches.
   typedef char fake_num_cache_c[sizeof(std::__numpunct_cache<char>)]
   __attribute__ ((aligned(__alignof__(std::__numpunct_cache<char>))));
@@ -329,6 +339,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #if _GLIBCXX_NUM_UNICODE_FACETS != 0
     &codecvt<char16_t, char, mbstate_t>::id,
     &codecvt<char32_t, char, mbstate_t>::id,
+#ifdef _GLIBCXX_USE_CHAR8_T
+    &codecvt<char16_t, char8_t, mbstate_t>::id,
+    &codecvt<char32_t, char8_t, mbstate_t>::id,
+#endif
 #endif
     0
   };
@@ -536,6 +550,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #if _GLIBCXX_NUM_UNICODE_FACETS != 0
     _M_init_facet(new (&codecvt_c16) codecvt<char16_t, char, mbstate_t>(1));
     _M_init_facet(new (&codecvt_c32) codecvt<char32_t, char, mbstate_t>(1));
+
+#ifdef _GLIBCXX_USE_CHAR8_T
+    _M_init_facet(new (&codecvt_c16_c8) codecvt<char16_t, char8_t, mbstate_t>(1));
+    _M_init_facet(new (&codecvt_c32_c8) codecvt<char32_t, char8_t, mbstate_t>(1));
+#endif
+
 #endif
 
 #if _GLIBCXX_USE_DUAL_ABI
diff --git a/libstdc++-v3/src/c++98/localename.cc b/libstdc++-v3/src/c++98/localename.cc
index 38290f0b8fe..4e9c5e6c988 100644
--- a/libstdc++-v3/src/c++98/localename.cc
+++ b/libstdc++-v3/src/c++98/localename.cc
@@ -272,6 +272,12 @@ const int num_facets = _GLIBCXX_NUM_FACETS + _GLIBCXX_NUM_UNICODE_FACETS
 #if _GLIBCXX_NUM_UNICODE_FACETS != 0
         _M_init_facet(new codecvt<char16_t, char, mbstate_t>);
         _M_init_facet(new codecvt<char32_t, char, mbstate_t>);
+
+#ifdef _GLIBCXX_USE_CHAR8_T
+        _M_init_facet(new codecvt<char16_t, char8_t, mbstate_t>);
+        _M_init_facet(new codecvt<char32_t, char8_t, mbstate_t>);
+#endif
+
 #endif
 
 #if _GLIBCXX_USE_DUAL_ABI
diff --git a/libstdc++-v3/testsuite/util/testsuite_abi.cc b/libstdc++-v3/testsuite/util/testsuite_abi.cc
index 836b62b128d..a2d2cab3653 100644
--- a/libstdc++-v3/testsuite/util/testsuite_abi.cc
+++ b/libstdc++-v3/testsuite/util/testsuite_abi.cc
@@ -220,6 +220,7 @@ check_version(symbol& test, bool added)
       known_versions.push_back("CXXABI_1.3.9");
       known_versions.push_back("CXXABI_1.3.10");
       known_versions.push_back("CXXABI_1.3.11");
+      known_versions.push_back("CXXABI_1.3.12");
       known_versions.push_back("CXXABI_TM_1");
       known_versions.push_back("CXXABI_FLOAT128");
     }
@@ -238,7 +239,7 @@ check_version(symbol& test, bool added)
 
       // Check that added symbols are added in the latest pre-release version.
       bool latestp = (test.version_name == "GLIBCXX_3.4.26"
-		     || test.version_name == "CXXABI_1.3.11"
+		     || test.version_name == "CXXABI_1.3.12"
 		     || test.version_name == "CXXABI_FLOAT128"
 		     || test.version_name == "CXXABI_TM_1");
       if (added && !latestp)
diff mbox series

Patch

diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c
index 08632c382b7..5f2f8e865ca 100644
--- a/gcc/cp/name-lookup.c
+++ b/gcc/cp/name-lookup.c
@@ -5543,6 +5543,7 @@  get_std_name_hint (const char *name)
     {"basic_string", "<string>", cxx98},
     {"string", "<string>", cxx98},
     {"wstring", "<string>", cxx98},
+    {"u8string", "<string>", cxx2a},
     {"u16string", "<string>", cxx11},
     {"u32string", "<string>", cxx11},
     /* <string_view>.  */
diff --git a/libstdc++-v3/config/abi/pre/gnu-versioned-namespace.ver b/libstdc++-v3/config/abi/pre/gnu-versioned-namespace.ver
index c448b813331..b26cf1dc8ac 100644
--- a/libstdc++-v3/config/abi/pre/gnu-versioned-namespace.ver
+++ b/libstdc++-v3/config/abi/pre/gnu-versioned-namespace.ver
@@ -301,6 +301,11 @@  CXXABI_2.0 {
     _ZTSN10__cxxabiv120__si_class_type_infoE;
     _ZTSN10__cxxabiv121__vmi_class_type_infoE;
 
+    # typeinfo for char8_t
+    _ZTIDu;
+    _ZTIPDu;
+    _ZTIPKDu;
+
     # typeinfo for char16_t and char32_t
     _ZTIDs;
     _ZTIPDs;
diff --git a/libstdc++-v3/config/abi/pre/gnu.ver b/libstdc++-v3/config/abi/pre/gnu.ver
index e8cd286ef0c..b24ff3bf9ee 100644
--- a/libstdc++-v3/config/abi/pre/gnu.ver
+++ b/libstdc++-v3/config/abi/pre/gnu.ver
@@ -2055,6 +2055,18 @@  GLIBCXX_3.4.26 {
     _ZNSt13basic_filebufI[cw]St11char_traitsI[cw]EE4openEPKwSt13_Ios_Openmode;
 
     _ZN11__gnu_debug25_Safe_local_iterator_base16_M_attach_singleEPNS_19_Safe_sequence_baseEb;
+
+    # numeric_limits<char8_t>
+    _ZNSt14numeric_limitsIDuE[5-9]*;
+    _ZNSt14numeric_limitsIDuE1[0-7][hirt]*;
+    _ZNSt14numeric_limitsIDuE1[0-7]mi*;
+    _ZNSt14numeric_limitsIDuE1[0-7]max_e*;
+
+    # codecvt<char16_t, char8_t, mbstate_t>, codecvt<char32_t, char8_t, mbstate_t>
+    _ZNKSt7codecvtID[is]Du*;
+    _ZNSt7codecvtID[is]Du*;
+    _ZT[ISV]St7codecvtID[is]Du*E;
+
 } GLIBCXX_3.4.25;
 
 # Symbols in the support library (libsupc++) have their own tag.
@@ -2346,6 +2358,15 @@  CXXABI_1.3.11 {
 
 } CXXABI_1.3.10;
 
+CXXABI_1.3.12 {
+
+    # typeinfo for char8_t
+    _ZTIDu;
+    _ZTIPDu;
+    _ZTIPKDu;
+
+} CXXABI_1.3.11;
+
 # Symbols in the support library (libsupc++) supporting transactional memory.
 CXXABI_TM_1 {
 
diff --git a/libstdc++-v3/include/bits/atomic_base.h b/libstdc++-v3/include/bits/atomic_base.h
index 7a3354d9e6f..b3c8440491b 100644
--- a/libstdc++-v3/include/bits/atomic_base.h
+++ b/libstdc++-v3/include/bits/atomic_base.h
@@ -227,6 +227,7 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
   // atomic_ulong    unsigned long
   // atomic_llong    long long
   // atomic_ullong   unsigned long long
+  // atomic_char8_t  char8_t
   // atomic_char16_t char16_t
   // atomic_char32_t char32_t
   // atomic_wchar_t  wchar_t
diff --git a/libstdc++-v3/include/bits/basic_string.h b/libstdc++-v3/include/bits/basic_string.h
index ae6530fcdc9..9a62ed2ddb7 100644
--- a/libstdc++-v3/include/bits/basic_string.h
+++ b/libstdc++-v3/include/bits/basic_string.h
@@ -6676,6 +6676,23 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #endif
 #endif /* _GLIBCXX_COMPATIBILITY_CXX0X */
 
+#ifdef _GLIBCXX_USE_CHAR8_T
+  /// std::hash specialization for u8string.
+  template<>
+    struct hash<u8string>
+    : public __hash_base<size_t, u8string>
+    {
+      size_t
+      operator()(const u8string& __s) const noexcept
+      { return std::_Hash_impl::hash(__s.data(),
+                                     __s.length() * sizeof(char8_t)); }
+    };
+
+  template<>
+    struct __is_fast_hash<hash<u8string>> : std::false_type
+    { };
+#endif
+
   /// std::hash specialization for u16string.
   template<>
     struct hash<u16string>
@@ -6728,6 +6745,13 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { return basic_string<wchar_t>{__str, __len}; }
 #endif
 
+#ifdef _GLIBCXX_USE_CHAR8_T
+    _GLIBCXX_DEFAULT_ABI_TAG
+    inline basic_string<char8_t>
+    operator""s(const char8_t* __str, size_t __len)
+    { return basic_string<char8_t>{__str, __len}; }
+#endif
+
     _GLIBCXX_DEFAULT_ABI_TAG
     inline basic_string<char16_t>
     operator""s(const char16_t* __str, size_t __len)
diff --git a/libstdc++-v3/include/bits/c++config b/libstdc++-v3/include/bits/c++config
index d499d32b51e..3c119704566 100644
--- a/libstdc++-v3/include/bits/c++config
+++ b/libstdc++-v3/include/bits/c++config
@@ -617,6 +617,17 @@  namespace std
 # endif
 #endif
 
+// Unless explicitly specified, enable char8_t extensions only if the core
+// language char8_t feature macro is defined.
+#ifndef _GLIBCXX_USE_CHAR8_T
+# ifdef __cpp_char8_t
+#  define _GLIBCXX_USE_CHAR8_T 1
+# endif
+#endif
+#ifdef _GLIBCXX_USE_CHAR8_T
+# define __cpp_lib_char8_t 201803
+#endif
+
 /* Define if __float128 is supported on this host. */
 #if defined(__FLOAT128__) || defined(__SIZEOF_FLOAT128__)
 #define _GLIBCXX_USE_FLOAT128
diff --git a/libstdc++-v3/include/bits/char_traits.h b/libstdc++-v3/include/bits/char_traits.h
index 63e810715f8..c5490ac37ec 100644
--- a/libstdc++-v3/include/bits/char_traits.h
+++ b/libstdc++-v3/include/bits/char_traits.h
@@ -492,6 +492,115 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
   };
 #endif //_GLIBCXX_USE_WCHAR_T
 
+#ifdef _GLIBCXX_USE_CHAR8_T
+  template<>
+    struct char_traits<char8_t>
+    {
+      typedef char8_t           char_type;
+      typedef unsigned int      int_type;
+      typedef u8streampos       pos_type;
+      typedef streamoff         off_type;
+      typedef mbstate_t         state_type;
+
+      static _GLIBCXX17_CONSTEXPR void
+      assign(char_type& __c1, const char_type& __c2) _GLIBCXX_NOEXCEPT
+      { __c1 = __c2; }
+
+      static _GLIBCXX_CONSTEXPR bool
+      eq(const char_type& __c1, const char_type& __c2) _GLIBCXX_NOEXCEPT
+      { return __c1 == __c2; }
+
+      static _GLIBCXX_CONSTEXPR bool
+      lt(const char_type& __c1, const char_type& __c2) _GLIBCXX_NOEXCEPT
+      { return __c1 < __c2; }
+
+      static _GLIBCXX17_CONSTEXPR int
+      compare(const char_type* __s1, const char_type* __s2, size_t __n)
+      {
+#if __cplusplus > 201402
+	if (__builtin_constant_p(__n)
+	    && __constant_char_array_p(__s1, __n)
+	    && __constant_char_array_p(__s2, __n))
+	  return __gnu_cxx::char_traits<char_type>::compare(__s1, __s2, __n);
+#endif
+	if (__n == 0)
+	  return 0;
+	return __builtin_memcmp(__s1, __s2, __n);
+      }
+
+      static _GLIBCXX17_CONSTEXPR size_t
+      length(const char_type* __s)
+      {
+#if __cplusplus > 201402
+	if (__constant_string_p(__s))
+	  return __gnu_cxx::char_traits<char_type>::length(__s);
+#endif
+	size_t __i = 0;
+	while (!eq(__s[__i], char_type()))
+	  ++__i;
+	return __i;
+      }
+
+      static _GLIBCXX17_CONSTEXPR const char_type*
+      find(const char_type* __s, size_t __n, const char_type& __a)
+      {
+#if __cplusplus > 201402
+	if (__builtin_constant_p(__n)
+	    && __builtin_constant_p(__a)
+	    && __constant_char_array_p(__s, __n))
+	  return __gnu_cxx::char_traits<char_type>::find(__s, __n, __a);
+#endif
+	if (__n == 0)
+	  return 0;
+	return static_cast<const char_type*>(__builtin_memchr(__s, __a, __n));
+      }
+
+      static char_type*
+      move(char_type* __s1, const char_type* __s2, size_t __n)
+      {
+	if (__n == 0)
+	  return __s1;
+	return static_cast<char_type*>(__builtin_memmove(__s1, __s2, __n));
+      }
+
+      static char_type*
+      copy(char_type* __s1, const char_type* __s2, size_t __n)
+      {
+	if (__n == 0)
+	  return __s1;
+	return static_cast<char_type*>(__builtin_memcpy(__s1, __s2, __n));
+      }
+
+      static char_type*
+      assign(char_type* __s, size_t __n, char_type __a)
+      {
+	if (__n == 0)
+	  return __s;
+	return static_cast<char_type*>(__builtin_memset(__s, __a, __n));
+      }
+
+      static _GLIBCXX_CONSTEXPR char_type
+      to_char_type(const int_type& __c) _GLIBCXX_NOEXCEPT
+      { return char_type(__c); }
+
+      static _GLIBCXX_CONSTEXPR int_type
+      to_int_type(const char_type& __c) _GLIBCXX_NOEXCEPT
+      { return int_type(__c); }
+
+      static _GLIBCXX_CONSTEXPR bool
+      eq_int_type(const int_type& __c1, const int_type& __c2) _GLIBCXX_NOEXCEPT
+      { return __c1 == __c2; }
+
+      static _GLIBCXX_CONSTEXPR int_type
+      eof() _GLIBCXX_NOEXCEPT
+      { return static_cast<int_type>(-1); }
+
+      static _GLIBCXX_CONSTEXPR int_type
+      not_eof(const int_type& __c) _GLIBCXX_NOEXCEPT
+      { return eq_int_type(__c, eof()) ? 0 : __c; }
+    };
+#endif //_GLIBCXX_USE_CHAR8_T
+
 _GLIBCXX_END_NAMESPACE_VERSION
 } // namespace
 
diff --git a/libstdc++-v3/include/bits/codecvt.h b/libstdc++-v3/include/bits/codecvt.h
index bafa28c3a00..b99d54af2f9 100644
--- a/libstdc++-v3/include/bits/codecvt.h
+++ b/libstdc++-v3/include/bits/codecvt.h
@@ -573,6 +573,122 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
       do_max_length() const throw();
     };
 
+#ifdef _GLIBCXX_USE_CHAR8_T
+  /** @brief  Class codecvt<char16_t, char8_t, mbstate_t> specialization.
+   *
+   *  Converts between UTF-16 and UTF-8.
+   */
+  template<>
+    class codecvt<char16_t, char8_t, mbstate_t>
+    : public __codecvt_abstract_base<char16_t, char8_t, mbstate_t>
+    {
+    public:
+      // Types:
+      typedef char16_t			intern_type;
+      typedef char8_t			extern_type;
+      typedef mbstate_t			state_type;
+
+    public:
+      static locale::id			id;
+
+      explicit
+      codecvt(size_t __refs = 0)
+      : __codecvt_abstract_base<char16_t, char8_t, mbstate_t>(__refs) { }
+
+    protected:
+      virtual
+      ~codecvt();
+
+      virtual result
+      do_out(state_type& __state, const intern_type* __from,
+	     const intern_type* __from_end, const intern_type*& __from_next,
+	     extern_type* __to, extern_type* __to_end,
+	     extern_type*& __to_next) const;
+
+      virtual result
+      do_unshift(state_type& __state,
+		 extern_type* __to, extern_type* __to_end,
+		 extern_type*& __to_next) const;
+
+      virtual result
+      do_in(state_type& __state,
+	     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;
+
+      virtual
+      int do_encoding() const throw();
+
+      virtual
+      bool do_always_noconv() const throw();
+
+      virtual
+      int do_length(state_type&, const extern_type* __from,
+		    const extern_type* __end, size_t __max) const;
+
+      virtual int
+      do_max_length() const throw();
+    };
+
+  /** @brief  Class codecvt<char32_t, char8_t, mbstate_t> specialization.
+   *
+   *  Converts between UTF-32 and UTF-8.
+   */
+  template<>
+    class codecvt<char32_t, char8_t, mbstate_t>
+    : public __codecvt_abstract_base<char32_t, char8_t, mbstate_t>
+    {
+    public:
+      // Types:
+      typedef char32_t			intern_type;
+      typedef char8_t			extern_type;
+      typedef mbstate_t			state_type;
+
+    public:
+      static locale::id			id;
+
+      explicit
+      codecvt(size_t __refs = 0)
+      : __codecvt_abstract_base<char32_t, char8_t, mbstate_t>(__refs) { }
+
+    protected:
+      virtual
+      ~codecvt();
+
+      virtual result
+      do_out(state_type& __state, const intern_type* __from,
+	     const intern_type* __from_end, const intern_type*& __from_next,
+	     extern_type* __to, extern_type* __to_end,
+	     extern_type*& __to_next) const;
+
+      virtual result
+      do_unshift(state_type& __state,
+		 extern_type* __to, extern_type* __to_end,
+		 extern_type*& __to_next) const;
+
+      virtual result
+      do_in(state_type& __state,
+	     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;
+
+      virtual
+      int do_encoding() const throw();
+
+      virtual
+      bool do_always_noconv() const throw();
+
+      virtual
+      int do_length(state_type&, const extern_type* __from,
+		    const extern_type* __end, size_t __max) const;
+
+      virtual int
+      do_max_length() const throw();
+    };
+#endif // _GLIBCXX_USE_CHAR8_T
+
 #endif // C++11
 
   /// class codecvt_byname [22.2.1.6].
@@ -639,6 +755,45 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
       virtual
       ~codecvt_byname() { }
     };
+
+#if defined(_GLIBCXX_USE_CHAR8_T)
+  template<>
+    class codecvt_byname<char16_t, char8_t, mbstate_t>
+    : public codecvt<char16_t, char8_t, mbstate_t>
+    {
+    public:
+      explicit
+      codecvt_byname(const char* __s, size_t __refs = 0)
+      : codecvt<char16_t, char8_t, mbstate_t>(__refs) { }
+
+      explicit
+      codecvt_byname(const string& __s, size_t __refs = 0)
+      : codecvt_byname(__s.c_str(), __refs) { }
+
+    protected:
+      virtual
+      ~codecvt_byname() { }
+    };
+
+  template<>
+    class codecvt_byname<char32_t, char8_t, mbstate_t>
+    : public codecvt<char32_t, char8_t, mbstate_t>
+    {
+    public:
+      explicit
+      codecvt_byname(const char* __s, size_t __refs = 0)
+      : codecvt<char32_t, char8_t, mbstate_t>(__refs) { }
+
+      explicit
+      codecvt_byname(const string& __s, size_t __refs = 0)
+      : codecvt_byname(__s.c_str(), __refs) { }
+
+    protected:
+      virtual
+      ~codecvt_byname() { }
+    };
+#endif
+
 #endif // C++11
 
   // Inhibit implicit instantiations for required instantiations,
@@ -669,6 +824,12 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #if __cplusplus >= 201103L
   extern template class codecvt_byname<char16_t, char, mbstate_t>;
   extern template class codecvt_byname<char32_t, char, mbstate_t>;
+
+#if defined(_GLIBCXX_USE_CHAR8_T)
+  extern template class codecvt_byname<char16_t, char8_t, mbstate_t>;
+  extern template class codecvt_byname<char32_t, char8_t, mbstate_t>;
+#endif
+
 #endif
 
 #endif
diff --git a/libstdc++-v3/include/bits/cpp_type_traits.h b/libstdc++-v3/include/bits/cpp_type_traits.h
index 960d469f412..f4c655bb848 100644
--- a/libstdc++-v3/include/bits/cpp_type_traits.h
+++ b/libstdc++-v3/include/bits/cpp_type_traits.h
@@ -48,7 +48,7 @@ 
 // so function return values won't work:  We need compile-time entities.
 // We're left with types and constant  integral expressions.
 // Secondly, from the point of view of ease of use, type-based compile-time
-// information is -not- *that* convenient.  On has to write lots of
+// information is -not- *that* convenient.  One has to write lots of
 // overloaded functions and to hope that the compiler will select the right
 // one. As a net effect, the overall structure isn't very clear at first
 // glance.
@@ -171,6 +171,15 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
     };
 # endif
 
+#ifdef _GLIBCXX_USE_CHAR8_T
+  template<>
+    struct __is_integer<char8_t>
+    {
+      enum { __value = 1 };
+      typedef __true_type __type;
+    };
+#endif
+
 #if __cplusplus >= 201103L
   template<>
     struct __is_integer<char16_t>
diff --git a/libstdc++-v3/include/bits/fs_path.h b/libstdc++-v3/include/bits/fs_path.h
index e3938d06d59..af6ac59a968 100644
--- a/libstdc++-v3/include/bits/fs_path.h
+++ b/libstdc++-v3/include/bits/fs_path.h
@@ -67,8 +67,13 @@  _GLIBCXX_BEGIN_NAMESPACE_CXX11
   {
     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>>;
+	= __or_<is_same<_Ch, char>,
+#ifdef _GLIBCXX_USE_CHAR8_T
+		is_same<_Ch, char8_t>,
+#endif
+		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>>
@@ -301,7 +306,11 @@  _GLIBCXX_BEGIN_NAMESPACE_CXX11
 #if _GLIBCXX_USE_WCHAR_T
     std::wstring   wstring() const;
 #endif
+#ifdef _GLIBCXX_USE_CHAR8_T
+    std::u8string  u8string() const;
+#else
     std::string    u8string() const;
+#endif // _GLIBCXX_USE_CHAR8_T
     std::u16string u16string() const;
     std::u32string u32string() const;
 
@@ -315,7 +324,11 @@  _GLIBCXX_BEGIN_NAMESPACE_CXX11
 #if _GLIBCXX_USE_WCHAR_T
     std::wstring   generic_wstring() const;
 #endif
+#ifdef _GLIBCXX_USE_CHAR8_T
+    std::u8string  generic_u8string() const;
+#else
     std::string    generic_u8string() const;
+#endif // _GLIBCXX_USE_CHAR8_T
     std::u16string generic_u16string() const;
     std::u32string generic_u32string() const;
 
@@ -666,10 +679,22 @@  _GLIBCXX_BEGIN_NAMESPACE_CXX11
       static string_type
       _S_convert(const _CharT* __f, const _CharT* __l)
       {
-	std::codecvt_utf8<_CharT> __cvt;
-	std::string __str;
-	if (__str_codecvt_out(__f, __l, __str, __cvt))
-	  return __str;
+#ifdef _GLIBCXX_USE_CHAR8_T
+	if constexpr (is_same_v<_CharT, char8_t>)
+	  {
+	    string_type __str(__f, __l);
+	    return __str;
+	  }
+	else
+	  {
+#endif
+	    std::codecvt_utf8<_CharT> __cvt;
+	    std::string __str;
+	    if (__str_codecvt_out(__f, __l, __str, __cvt))
+	      return __str;
+#ifdef _GLIBCXX_USE_CHAR8_T
+	  }
+#endif
 	_GLIBCXX_THROW_OR_ABORT(filesystem_error(
 	      "Cannot convert character sequence",
 	      std::make_error_code(errc::illegal_byte_sequence)));
@@ -850,6 +875,15 @@  _GLIBCXX_BEGIN_NAMESPACE_CXX11
 	{
 	  if constexpr (is_same_v<_CharT, char>)
 	    return __u8str;
+#ifdef _GLIBCXX_USE_CHAR8_T
+	  else if constexpr (is_same_v<_CharT, char8_t>)
+	    {
+	      const char* __f = __u8str.data();
+	      const char* __l = __f + __u8str.size();
+	      _WString __wstr(__f, __l);
+	      return __wstr;
+	    }
+#endif
 	  else
 	    {
 	      _WString __wstr;
@@ -862,10 +896,22 @@  _GLIBCXX_BEGIN_NAMESPACE_CXX11
 	    }
 	}
 #else
-      codecvt_utf8<_CharT> __cvt;
-      basic_string<_CharT, _Traits, _Allocator> __wstr{__a};
-      if (__str_codecvt_in(__first, __last, __wstr, __cvt))
-	return __wstr;
+#ifdef _GLIBCXX_USE_CHAR8_T
+      if constexpr (is_same_v<_CharT, char8_t>)
+	{
+	  basic_string<_CharT, _Traits, _Allocator> __wstr{__first, __last, __a};
+	  return __wstr;
+	}
+      else
+	{
+#endif
+	  codecvt_utf8<_CharT> __cvt;
+	  basic_string<_CharT, _Traits, _Allocator> __wstr{__a};
+	  if (__str_codecvt_in(__first, __last, __wstr, __cvt))
+	    return __wstr;
+#ifdef _GLIBCXX_USE_CHAR8_T
+	}
+#endif
 #endif
       _GLIBCXX_THROW_OR_ABORT(filesystem_error(
 	    "Cannot convert character sequence",
@@ -899,6 +945,10 @@  _GLIBCXX_BEGIN_NAMESPACE_CXX11
   path::wstring() const { return string<wchar_t>(); }
 #endif
 
+#ifdef _GLIBCXX_USE_CHAR8_T
+  inline std::u8string
+  path::u8string() const { return string<char8_t>(); }
+#else
   inline std::string
   path::u8string() const
   {
@@ -917,6 +967,7 @@  _GLIBCXX_BEGIN_NAMESPACE_CXX11
     return _M_pathname;
 #endif
   }
+#endif // _GLIBCXX_USE_CHAR8_T
 
   inline std::u16string
   path::u16string() const { return string<char16_t>(); }
@@ -966,9 +1017,15 @@  _GLIBCXX_BEGIN_NAMESPACE_CXX11
   { return generic_string<wchar_t>(); }
 #endif
 
+#ifdef _GLIBCXX_USE_CHAR8_T
+  inline std::u8string
+  path::generic_u8string() const
+  { return generic_string<char8_t>(); }
+#else
   inline std::string
   path::generic_u8string() const
   { return generic_string(); }
+#endif
 
   inline std::u16string
   path::generic_u16string() const
diff --git a/libstdc++-v3/include/bits/functional_hash.h b/libstdc++-v3/include/bits/functional_hash.h
index 0f20b956b76..658b9606ea1 100644
--- a/libstdc++-v3/include/bits/functional_hash.h
+++ b/libstdc++-v3/include/bits/functional_hash.h
@@ -135,6 +135,11 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
   /// Explicit specialization for wchar_t.
   _Cxx_hashtable_define_trivial_hash(wchar_t)
 
+#ifdef _GLIBCXX_USE_CHAR8_T
+  /// Explicit specialization for char8_t.
+  _Cxx_hashtable_define_trivial_hash(char8_t)
+#endif
+
   /// Explicit specialization for char16_t.
   _Cxx_hashtable_define_trivial_hash(char16_t)
 
diff --git a/libstdc++-v3/include/bits/locale_conv.h b/libstdc++-v3/include/bits/locale_conv.h
index e9b684b4f98..a09898a406f 100644
--- a/libstdc++-v3/include/bits/locale_conv.h
+++ b/libstdc++-v3/include/bits/locale_conv.h
@@ -158,6 +158,39 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
       return __str_codecvt_out(__first, __last, __outstr, __cvt, __state, __n);
     }
 
+#ifdef _GLIBCXX_USE_CHAR8_T
+
+  // Convert wide character string to narrow.
+  template<typename _CharT, typename _Traits, typename _Alloc, typename _State>
+    inline bool
+    __str_codecvt_out(const _CharT* __first, const _CharT* __last,
+		      basic_string<char8_t, _Traits, _Alloc>& __outstr,
+		      const codecvt<_CharT, char8_t, _State>& __cvt,
+		      _State& __state, size_t& __count)
+    {
+      using _Codecvt = codecvt<_CharT, char8_t, _State>;
+      using _ConvFn
+	= codecvt_base::result
+	  (_Codecvt::*)(_State&, const _CharT*, const _CharT*, const _CharT*&,
+			char8_t*, char8_t*, char8_t*&) const;
+      _ConvFn __fn = &codecvt<_CharT, char8_t, _State>::out;
+      return __do_str_codecvt(__first, __last, __outstr, __cvt, __state,
+			      __count, __fn);
+    }
+
+  template<typename _CharT, typename _Traits, typename _Alloc, typename _State>
+    inline bool
+    __str_codecvt_out(const _CharT* __first, const _CharT* __last,
+		      basic_string<char8_t, _Traits, _Alloc>& __outstr,
+		      const codecvt<_CharT, char8_t, _State>& __cvt)
+    {
+      _State __state = {};
+      size_t __n;
+      return __str_codecvt_out(__first, __last, __outstr, __cvt, __state, __n);
+    }
+
+#endif  // _GLIBCXX_USE_CHAR8_T
+
 #ifdef _GLIBCXX_USE_WCHAR_T
 
 _GLIBCXX_BEGIN_NAMESPACE_CXX11
diff --git a/libstdc++-v3/include/bits/locale_facets.h b/libstdc++-v3/include/bits/locale_facets.h
index f6e0283fec9..a5f53a3defa 100644
--- a/libstdc++-v3/include/bits/locale_facets.h
+++ b/libstdc++-v3/include/bits/locale_facets.h
@@ -59,7 +59,11 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 # define  _GLIBCXX_NUM_FACETS 14
 # define  _GLIBCXX_NUM_CXX11_FACETS 8
 #endif
-#define _GLIBCXX_NUM_UNICODE_FACETS 2
+#ifdef _GLIBCXX_USE_CHAR8_T
+# define _GLIBCXX_NUM_UNICODE_FACETS 4
+#else
+# define _GLIBCXX_NUM_UNICODE_FACETS 2
+#endif
 
   // Convert string to numeric value of type _Tp and store results.
   // NB: This is specialized for all required types, there is no
diff --git a/libstdc++-v3/include/bits/localefwd.h b/libstdc++-v3/include/bits/localefwd.h
index e8690638c7a..e2a725f7ef0 100644
--- a/libstdc++-v3/include/bits/localefwd.h
+++ b/libstdc++-v3/include/bits/localefwd.h
@@ -139,6 +139,14 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<> class codecvt<char, char, mbstate_t>;
 #ifdef _GLIBCXX_USE_WCHAR_T
   template<> class codecvt<wchar_t, char, mbstate_t>;
+#endif
+#if __cplusplus >= 201103L
+  template<> class codecvt<char16_t, char, mbstate_t>;
+  template<> class codecvt<char32_t, char, mbstate_t>;
+#ifdef _GLIBCXX_USE_CHAR8_T
+  template<> class codecvt<char16_t, char8_t, mbstate_t>;
+  template<> class codecvt<char32_t, char8_t, mbstate_t>;
+#endif
 #endif
   template<typename _InternT, typename _ExternT, typename _StateT>
     class codecvt_byname;
diff --git a/libstdc++-v3/include/bits/postypes.h b/libstdc++-v3/include/bits/postypes.h
index 8abdbf02322..89ab9e8d548 100644
--- a/libstdc++-v3/include/bits/postypes.h
+++ b/libstdc++-v3/include/bits/postypes.h
@@ -235,6 +235,11 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
   /// File position for wchar_t streams.
   typedef fpos<mbstate_t> wstreampos;
 
+#ifdef _GLIBCXX_USE_CHAR8_T
+  /// File position for char8_t streams.
+  typedef fpos<mbstate_t> u8streampos;
+#endif
+
 #if __cplusplus >= 201103L
   /// File position for char16_t streams.
   typedef fpos<mbstate_t> u16streampos;
diff --git a/libstdc++-v3/include/bits/stringfwd.h b/libstdc++-v3/include/bits/stringfwd.h
index 2b7f4612cbc..98f06f98d6b 100644
--- a/libstdc++-v3/include/bits/stringfwd.h
+++ b/libstdc++-v3/include/bits/stringfwd.h
@@ -58,6 +58,10 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<> struct char_traits<wchar_t>;
 #endif
 
+#ifdef _GLIBCXX_USE_CHAR8_T
+  template<> struct char_traits<char8_t>;
+#endif
+
 #if __cplusplus >= 201103L
   template<> struct char_traits<char16_t>;
   template<> struct char_traits<char32_t>;
@@ -79,6 +83,11 @@  _GLIBCXX_END_NAMESPACE_CXX11
   typedef basic_string<wchar_t> wstring;   
 #endif
 
+#ifdef _GLIBCXX_USE_CHAR8_T
+  /// A string of @c char8_t
+  typedef basic_string<char8_t> u8string;
+#endif
+
 #if __cplusplus >= 201103L
   /// A string of @c char16_t
   typedef basic_string<char16_t> u16string; 
diff --git a/libstdc++-v3/include/c_global/cstddef b/libstdc++-v3/include/c_global/cstddef
index b6d4a13c0b1..a6002236814 100644
--- a/libstdc++-v3/include/c_global/cstddef
+++ b/libstdc++-v3/include/c_global/cstddef
@@ -75,6 +75,9 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<> struct __byte_operand<unsigned char> { using __type = byte; };
 #ifdef _GLIBCXX_USE_WCHAR_T
   template<> struct __byte_operand<wchar_t> { using __type = byte; };
+#endif
+#ifdef _GLIBCXX_USE_CHAR8_T
+  template<> struct __byte_operand<char8_t> { using __type = byte; };
 #endif
   template<> struct __byte_operand<char16_t> { using __type = byte; };
   template<> struct __byte_operand<char32_t> { using __type = byte; };
diff --git a/libstdc++-v3/include/experimental/bits/fs_path.h b/libstdc++-v3/include/experimental/bits/fs_path.h
index 653b4a3fe85..ad346065e28 100644
--- a/libstdc++-v3/include/experimental/bits/fs_path.h
+++ b/libstdc++-v3/include/experimental/bits/fs_path.h
@@ -82,8 +82,13 @@  _GLIBCXX_BEGIN_NAMESPACE_CXX11
     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>>;
+	= __or_<is_same<_Ch, char>,
+		is_same<_Ch, wchar_t>,
+#ifdef _GLIBCXX_USE_CHAR8_T
+		is_same<_Ch, char8_t>,
+#endif
+		is_same<_Ch, char16_t>,
+		is_same<_Ch, char32_t>>;
 
     template<typename _Iter,
 	     typename _Iter_traits = std::iterator_traits<_Iter>>
@@ -323,7 +328,11 @@  _GLIBCXX_BEGIN_NAMESPACE_CXX11
 #if _GLIBCXX_USE_WCHAR_T
     std::wstring   wstring() const;
 #endif
+#ifdef _GLIBCXX_USE_CHAR8_T
+    std::u8string  u8string() const;
+#else
     std::string    u8string() const;
+#endif // _GLIBCXX_USE_CHAR8_T
     std::u16string u16string() const;
     std::u32string u32string() const;
 
@@ -337,7 +346,11 @@  _GLIBCXX_BEGIN_NAMESPACE_CXX11
 #if _GLIBCXX_USE_WCHAR_T
     std::wstring   generic_wstring() const;
 #endif
+#ifdef _GLIBCXX_USE_CHAR8_T
+    std::u8string  generic_u8string() const;
+#else
     std::string    generic_u8string() const;
+#endif // _GLIBCXX_USE_CHAR8_T
     std::u16string generic_u16string() const;
     std::u32string generic_u32string() const;
 
@@ -672,10 +685,22 @@  _GLIBCXX_BEGIN_NAMESPACE_CXX11
       static string_type
       _S_convert(const _CharT* __f, const _CharT* __l)
       {
-	std::codecvt_utf8<_CharT> __cvt;
-	std::string __str;
-	if (__str_codecvt_out(__f, __l, __str, __cvt))
-	  return __str;
+#ifdef _GLIBCXX_USE_CHAR8_T
+	if constexpr (is_same<_CharT, char8_t>::value)
+	  {
+	    string_type __str(__f, __l);
+	    return __str;
+	  }
+	else
+	  {
+#endif
+	    std::codecvt_utf8<_CharT> __cvt;
+	    std::string __str;
+	    if (__str_codecvt_out(__f, __l, __str, __cvt))
+	      return __str;
+#ifdef _GLIBCXX_USE_CHAR8_T
+	  }
+#endif
 	_GLIBCXX_THROW_OR_ABORT(filesystem_error(
 	      "Cannot convert character sequence",
 	      std::make_error_code(errc::illegal_byte_sequence)));
@@ -865,12 +890,24 @@  _GLIBCXX_BEGIN_NAMESPACE_CXX11
 	    _WString*
 	    operator()(const _String& __from, _WString& __to, false_type)
 	    {
-	      // use codecvt_utf8<_CharT> to convert UTF-8 to wide string
-	      codecvt_utf8<_CharT> __cvt;
-	      const char* __f = __from.data();
-	      const char* __l = __f + __from.size();
-	      if (__str_codecvt_in(__f, __l, __to, __cvt))
-		return std::__addressof(__to);
+#ifdef _GLIBCXX_USE_CHAR8_T
+	      if constexpr (is_same<_CharT, char8_t>::value)
+	        {
+	          __to.assign(__from.begin(), __from.end());
+	          return std::__addressof(__to);
+	        }
+	      else
+	        {
+#endif
+	          // use codecvt_utf8<_CharT> to convert UTF-8 to wide string
+	          codecvt_utf8<_CharT> __cvt;
+	          const char* __f = __from.data();
+	          const char* __l = __f + __from.size();
+	          if (__str_codecvt_in(__f, __l, __to, __cvt))
+		    return std::__addressof(__to);
+#ifdef _GLIBCXX_USE_CHAR8_T
+	        }
+#endif
 	      return nullptr;
 	    }
 	  } __dispatch;
@@ -879,10 +916,22 @@  _GLIBCXX_BEGIN_NAMESPACE_CXX11
 	    return *__p;
 	}
 #else
-      codecvt_utf8<_CharT> __cvt;
-      basic_string<_CharT, _Traits, _Allocator> __wstr{__a};
-      if (__str_codecvt_in(__first, __last, __wstr, __cvt))
-	return __wstr;
+#ifdef _GLIBCXX_USE_CHAR8_T
+      if constexpr (is_same<_CharT, char8_t>::value)
+        {
+          basic_string<_CharT, _Traits, _Allocator> __wstr{__first, __last, __a};
+          return __wstr;
+        }
+      else
+        {
+#endif
+          codecvt_utf8<_CharT> __cvt;
+          basic_string<_CharT, _Traits, _Allocator> __wstr{__a};
+          if (__str_codecvt_in(__first, __last, __wstr, __cvt))
+	    return __wstr;
+#ifdef _GLIBCXX_USE_CHAR8_T
+        }
+#endif
 #endif
       _GLIBCXX_THROW_OR_ABORT(filesystem_error(
 	    "Cannot convert character sequence",
@@ -897,6 +946,10 @@  _GLIBCXX_BEGIN_NAMESPACE_CXX11
   path::wstring() const { return string<wchar_t>(); }
 #endif
 
+#ifdef _GLIBCXX_USE_CHAR8_T
+  inline std::u8string
+  path::u8string() const { return string<char8_t>(); }
+#else
   inline std::string
   path::u8string() const
   {
@@ -915,6 +968,7 @@  _GLIBCXX_BEGIN_NAMESPACE_CXX11
     return _M_pathname;
 #endif
   }
+#endif // _GLIBCXX_USE_CHAR8_T
 
   inline std::u16string
   path::u16string() const { return string<char16_t>(); }
@@ -936,8 +990,13 @@  _GLIBCXX_BEGIN_NAMESPACE_CXX11
   path::generic_wstring() const { return wstring(); }
 #endif
 
+#ifdef _GLIBCXX_USE_CHAR8_T
+  inline std::u8string
+  path::generic_u8string() const { return u8string(); }
+#else
   inline std::string
   path::generic_u8string() const { return u8string(); }
+#endif
 
   inline std::u16string
   path::generic_u16string() const { return u16string(); }
diff --git a/libstdc++-v3/include/experimental/string b/libstdc++-v3/include/experimental/string
index 5a96bf78d73..d1ee5d369b3 100644
--- a/libstdc++-v3/include/experimental/string
+++ b/libstdc++-v3/include/experimental/string
@@ -73,6 +73,9 @@  inline namespace fundamentals_v2
     // basic_string typedef names using polymorphic allocator in namespace
     // std::experimental::pmr
     typedef basic_string<char> string;
+#ifdef _GLIBCXX_USE_CHAR8_T
+    typedef basic_string<char8_t> u8string;
+#endif
     typedef basic_string<char16_t> u16string;
     typedef basic_string<char32_t> u32string;
     typedef basic_string<wchar_t> wstring;
diff --git a/libstdc++-v3/include/experimental/string_view b/libstdc++-v3/include/experimental/string_view
index b3bc1a9fb4f..0cbdb663cca 100644
--- a/libstdc++-v3/include/experimental/string_view
+++ b/libstdc++-v3/include/experimental/string_view
@@ -565,6 +565,9 @@  inline namespace fundamentals_v1
   using string_view = basic_string_view<char>;
 #ifdef _GLIBCXX_USE_WCHAR_T
   using wstring_view = basic_string_view<wchar_t>;
+#endif
+#ifdef _GLIBCXX_USE_CHAR8_T
+  using u8string_view = basic_string_view<char8_t>;
 #endif
   using u16string_view = basic_string_view<char16_t>;
   using u32string_view = basic_string_view<char32_t>;
@@ -605,6 +608,21 @@  inline namespace fundamentals_v1
     { };
 #endif
 
+#ifdef _GLIBCXX_USE_CHAR8_T
+  template<>
+    struct hash<experimental::u8string_view>
+    : public __hash_base<size_t, experimental::u8string_view>
+    {
+      size_t
+      operator()(const experimental::u8string_view& __s) const noexcept
+      { return std::_Hash_impl::hash(__s.data(), __s.length()); }
+    };
+
+  template<>
+    struct __is_fast_hash<hash<experimental::u8string_view>> : std::false_type
+    { };
+#endif
+
   template<>
     struct hash<experimental::u16string_view>
     : public __hash_base<size_t, experimental::u16string_view>
@@ -652,6 +670,12 @@  namespace experimental
     { return basic_string_view<wchar_t>{__str, __len}; }
 #endif
 
+#ifdef _GLIBCXX_USE_CHAR8_T
+    inline constexpr basic_string_view<char8_t>
+    operator""sv(const char8_t* __str, size_t __len) noexcept
+    { return basic_string_view<char8_t>{__str, __len}; }
+#endif
+
     inline constexpr basic_string_view<char16_t>
     operator""sv(const char16_t* __str, size_t __len) noexcept
     { return basic_string_view<char16_t>{__str, __len}; }
diff --git a/libstdc++-v3/include/std/atomic b/libstdc++-v3/include/std/atomic
index 002604676cd..fe0c141fe1f 100644
--- a/libstdc++-v3/include/std/atomic
+++ b/libstdc++-v3/include/std/atomic
@@ -904,6 +904,31 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #endif
     };
 
+#ifdef _GLIBCXX_USE_CHAR8_T
+  /// Explicit specialization for char8_t.
+  template<>
+    struct atomic<char8_t> : __atomic_base<char8_t>
+    {
+      typedef char8_t 			__integral_type;
+      typedef __atomic_base<char8_t> 	__base_type;
+
+      atomic() noexcept = default;
+      ~atomic() noexcept = default;
+      atomic(const atomic&) = delete;
+      atomic& operator=(const atomic&) = delete;
+      atomic& operator=(const atomic&) volatile = delete;
+
+      constexpr atomic(__integral_type __i) noexcept : __base_type(__i) { }
+
+      using __base_type::operator __integral_type;
+      using __base_type::operator=;
+
+#if __cplusplus > 201402L
+    static constexpr bool is_always_lock_free = ATOMIC_CHAR8_T_LOCK_FREE == 2;
+#endif
+    };
+#endif
+
   /// Explicit specialization for char16_t.
   template<>
     struct atomic<char16_t> : __atomic_base<char16_t>
@@ -990,6 +1015,11 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
   /// atomic_wchar_t
   typedef atomic<wchar_t>		atomic_wchar_t;
 
+#ifdef _GLIBCXX_USE_CHAR8_T
+  /// atomic_char8_t
+  typedef atomic<char8_t>		atomic_char8_t;
+#endif
+
   /// atomic_char16_t
   typedef atomic<char16_t>		atomic_char16_t;
 
diff --git a/libstdc++-v3/include/std/charconv b/libstdc++-v3/include/std/charconv
index 922c2c7e25e..852e8b2b696 100644
--- a/libstdc++-v3/include/std/charconv
+++ b/libstdc++-v3/include/std/charconv
@@ -66,6 +66,9 @@  namespace __detail
 	  __not_<__is_one_of<_Tp, bool, char16_t, char32_t
 #if _GLIBCXX_USE_WCHAR_T
 	  , wchar_t
+#endif
+#if _GLIBCXX_USE_CHAR8_T
+	  , char8_t
 #endif
 	    >>>;
 
diff --git a/libstdc++-v3/include/std/limits b/libstdc++-v3/include/std/limits
index e8eb6a1e0c4..0bf635e7b92 100644
--- a/libstdc++-v3/include/std/limits
+++ b/libstdc++-v3/include/std/limits
@@ -374,6 +374,7 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   // Now there follow 16 explicit specializations.  Yes, 16.  Make sure
   // you get the count right. (18 in C++11 mode, with char16_t and char32_t.)
+  // (+1 if char8_t is enabled.)
 
   // _GLIBCXX_RESOLVE_LIB_DEFECTS
   // 184. numeric_limits<bool> wording problems
@@ -725,6 +726,69 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
        = round_toward_zero;
     };
 
+#if _GLIBCXX_USE_CHAR8_T
+  /// numeric_limits<char8_t> specialization.
+  template<>
+    struct numeric_limits<char8_t>
+    {
+      static constexpr bool is_specialized = true;
+
+      static constexpr char8_t
+      min() noexcept { return __glibcxx_min (char8_t); }
+
+      static constexpr char8_t
+      max() noexcept { return __glibcxx_max (char8_t); }
+
+      static constexpr char8_t
+      lowest() noexcept { return min(); }
+
+      static constexpr int digits = __glibcxx_digits (char8_t);
+      static constexpr int digits10 = __glibcxx_digits10 (char8_t);
+      static constexpr int max_digits10 = 0;
+      static constexpr bool is_signed = __glibcxx_signed (char8_t);
+      static constexpr bool is_integer = true;
+      static constexpr bool is_exact = true;
+      static constexpr int radix = 2;
+
+      static constexpr char8_t
+      epsilon() noexcept { return 0; }
+
+      static constexpr char8_t
+      round_error() noexcept { return 0; }
+
+      static constexpr int min_exponent = 0;
+      static constexpr int min_exponent10 = 0;
+      static constexpr int max_exponent = 0;
+      static constexpr int max_exponent10 = 0;
+
+      static constexpr bool has_infinity = false;
+      static constexpr bool has_quiet_NaN = false;
+      static constexpr bool has_signaling_NaN = false;
+      static constexpr float_denorm_style has_denorm = denorm_absent;
+      static constexpr bool has_denorm_loss = false;
+
+      static constexpr char8_t
+      infinity() noexcept { return char8_t(); }
+
+      static constexpr char8_t
+      quiet_NaN() noexcept { return char8_t(); }
+
+      static constexpr char8_t
+      signaling_NaN() noexcept { return char8_t(); }
+
+      static constexpr char8_t
+      denorm_min() noexcept { return char8_t(); }
+
+      static constexpr bool is_iec559 = false;
+      static constexpr bool is_bounded = true;
+      static constexpr bool is_modulo = !is_signed;
+
+      static constexpr bool traps = __glibcxx_integral_traps;
+      static constexpr bool tinyness_before = false;
+      static constexpr float_round_style round_style = round_toward_zero;
+    };
+#endif
+
 #if __cplusplus >= 201103L
   /// numeric_limits<char16_t> specialization.
   template<>
diff --git a/libstdc++-v3/include/std/string b/libstdc++-v3/include/std/string
index dd60df2ba6e..7fd29cc163a 100644
--- a/libstdc++-v3/include/std/string
+++ b/libstdc++-v3/include/std/string
@@ -62,6 +62,9 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
       using basic_string = std::basic_string<_CharT, _Traits,
 					     polymorphic_allocator<_CharT>>;
     using string    = basic_string<char>;
+#ifdef _GLIBCXX_USE_CHAR8_T
+    using u8string  = basic_string<char8_t>;
+#endif
     using u16string = basic_string<char16_t>;
     using u32string = basic_string<char32_t>;
 #ifdef _GLIBCXX_USE_WCHAR_T
diff --git a/libstdc++-v3/include/std/string_view b/libstdc++-v3/include/std/string_view
index 9e0f6a723e4..b7ee0a586f5 100644
--- a/libstdc++-v3/include/std/string_view
+++ b/libstdc++-v3/include/std/string_view
@@ -555,7 +555,9 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #ifdef _GLIBCXX_USE_WCHAR_T
   using wstring_view = basic_string_view<wchar_t>;
 #endif
-
+#ifdef _GLIBCXX_USE_CHAR8_T
+  using u8string_view = basic_string_view<char8_t>;
+#endif
   using u16string_view = basic_string_view<char16_t>;
   using u32string_view = basic_string_view<char32_t>;
 
@@ -593,6 +595,21 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { };
 #endif
 
+#ifdef _GLIBCXX_USE_CHAR8_T
+  template<>
+    struct hash<u8string_view>
+    : public __hash_base<size_t, u8string_view>
+    {
+      size_t
+      operator()(const u8string_view& __str) const noexcept
+      { return std::_Hash_impl::hash(__str.data(), __str.length()); }
+    };
+
+  template<>
+    struct __is_fast_hash<hash<u8string_view>> : std::false_type
+    { };
+#endif
+
   template<>
     struct hash<u16string_view>
     : public __hash_base<size_t, u16string_view>
@@ -637,6 +654,12 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { return basic_string_view<wchar_t>{__str, __len}; }
 #endif
 
+#ifdef _GLIBCXX_USE_CHAR8_T
+    inline constexpr basic_string_view<char8_t>
+    operator""sv(const char8_t* __str, size_t __len) noexcept
+    { return basic_string_view<char8_t>{__str, __len}; }
+#endif
+
     inline constexpr basic_string_view<char16_t>
     operator""sv(const char16_t* __str, size_t __len) noexcept
     { return basic_string_view<char16_t>{__str, __len}; }
diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 86b58ccf225..5a1c2c0e08a 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -234,6 +234,12 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
     : public true_type { };
 #endif
 
+#ifdef _GLIBCXX_USE_CHAR8_T
+  template<>
+    struct __is_integral_helper<char8_t>
+    : public true_type { };
+#endif
+
   template<>
     struct __is_integral_helper<char16_t>
     : public true_type { };
@@ -1673,8 +1679,8 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	= typename __match_cv_qualifiers<_Tp, __unsigned_type>::__type;
     };
 
-  // wchar_t, char16_t and char32_t are integral types but are neither
-  // signed integer types nor unsigned integer types, so must be
+  // wchar_t, char8_t, char16_t and char32_t are integral types but are
+  // neither signed integer types nor unsigned integer types, so must be
   // transformed to the unsigned integer type with the smallest rank.
   // Use the partial specialization for enumeration types to do that.
 #if defined(_GLIBCXX_USE_WCHAR_T)
@@ -1686,6 +1692,15 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
     };
 #endif
 
+#ifdef _GLIBCXX_USE_CHAR8_T
+  template<>
+    struct __make_unsigned<char8_t>
+    {
+      using __type
+	= typename __make_unsigned_selector<char8_t, false, true>::__type;
+    };
+#endif
+
   template<>
     struct __make_unsigned<char16_t>
     {
@@ -1803,6 +1818,15 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
     };
 #endif
 
+#if defined(_GLIBCXX_USE_CHAR8_T)
+  template<>
+    struct __make_signed<char8_t>
+    {
+      using __type
+	= typename __make_signed_selector<char8_t, false, true>::__type;
+    };
+#endif
+
   template<>
     struct __make_signed<char16_t>
     {
diff --git a/libstdc++-v3/libsupc++/atomic_lockfree_defines.h b/libstdc++-v3/libsupc++/atomic_lockfree_defines.h
index 2afa6dffb96..6da15823244 100644
--- a/libstdc++-v3/libsupc++/atomic_lockfree_defines.h
+++ b/libstdc++-v3/libsupc++/atomic_lockfree_defines.h
@@ -49,6 +49,9 @@ 
 #define ATOMIC_BOOL_LOCK_FREE		__GCC_ATOMIC_BOOL_LOCK_FREE
 #define ATOMIC_CHAR_LOCK_FREE		__GCC_ATOMIC_CHAR_LOCK_FREE
 #define ATOMIC_WCHAR_T_LOCK_FREE	__GCC_ATOMIC_WCHAR_T_LOCK_FREE
+#ifdef _GLIBCXX_USE_CHAR8_T
+#define ATOMIC_CHAR8_T_LOCK_FREE	__GCC_ATOMIC_CHAR8_T_LOCK_FREE
+#endif
 #define ATOMIC_CHAR16_T_LOCK_FREE	__GCC_ATOMIC_CHAR16_T_LOCK_FREE
 #define ATOMIC_CHAR32_T_LOCK_FREE	__GCC_ATOMIC_CHAR32_T_LOCK_FREE
 #define ATOMIC_SHORT_LOCK_FREE		__GCC_ATOMIC_SHORT_LOCK_FREE
diff --git a/libstdc++-v3/src/c++11/Makefile.am b/libstdc++-v3/src/c++11/Makefile.am
index a22258782cb..d926e172973 100644
--- a/libstdc++-v3/src/c++11/Makefile.am
+++ b/libstdc++-v3/src/c++11/Makefile.am
@@ -126,6 +126,16 @@  hashtable_c++0x.lo: hashtable_c++0x.cc
 hashtable_c++0x.o: hashtable_c++0x.cc
 	$(CXXCOMPILE) -fimplicit-templates -c $<
 
+# Use special rules for source files that require -fchar8_t.
+codecvt.lo: codecvt.cc
+	$(LTCXXCOMPILE) -fchar8_t -c $<
+codecvt.o: codecvt.cc
+	$(CXXCOMPILE) -fchar8_t -c $<
+limits.lo: limits.cc
+	$(LTCXXCOMPILE) -fchar8_t -c $<
+limits.o: limits.cc
+	$(CXXCOMPILE) -fchar8_t -c $<
+
 if ENABLE_DUAL_ABI
 # Rewrite the type info for __ios_failure.
 rewrite_ios_failure_typeinfo = sed -e '/^_*_ZTISt13__ios_failure:/,/_ZTVN10__cxxabiv120__si_class_type_infoE/s/_ZTVN10__cxxabiv120__si_class_type_infoE/_ZTVSt19__iosfail_type_info/'
diff --git a/libstdc++-v3/src/c++11/Makefile.in b/libstdc++-v3/src/c++11/Makefile.in
index d4c4b72a1ae..cec5bfad8ee 100644
--- a/libstdc++-v3/src/c++11/Makefile.in
+++ b/libstdc++-v3/src/c++11/Makefile.in
@@ -751,6 +751,16 @@  hashtable_c++0x.lo: hashtable_c++0x.cc
 hashtable_c++0x.o: hashtable_c++0x.cc
 	$(CXXCOMPILE) -fimplicit-templates -c $<
 
+# Use special rules for source files that require -fchar8_t.
+codecvt.lo: codecvt.cc
+	$(LTCXXCOMPILE) -fchar8_t -c $<
+codecvt.o: codecvt.cc
+	$(CXXCOMPILE) -fchar8_t -c $<
+limits.lo: limits.cc
+	$(LTCXXCOMPILE) -fchar8_t -c $<
+limits.o: limits.cc
+	$(CXXCOMPILE) -fchar8_t -c $<
+
 @ENABLE_DUAL_ABI_TRUE@cxx11-ios_failure-lt.s: cxx11-ios_failure.cc
 @ENABLE_DUAL_ABI_TRUE@	$(LTCXXCOMPILE) -S $< -o tmp-cxx11-ios_failure-lt.s
 @ENABLE_DUAL_ABI_TRUE@	-test -f tmp-cxx11-ios_failure-lt.o && mv -f tmp-cxx11-ios_failure-lt.o tmp-cxx11-ios_failure-lt.s
diff --git a/libstdc++-v3/src/c++11/codecvt.cc b/libstdc++-v3/src/c++11/codecvt.cc
index 503f2fe1ff3..fc9fd427ee5 100644
--- a/libstdc++-v3/src/c++11/codecvt.cc
+++ b/libstdc++-v3/src/c++11/codecvt.cc
@@ -193,8 +193,9 @@  namespace
     }
 
   // If generate_header is set in mode write out UTF-8 BOM.
+  template<typename C>
   bool
-  write_utf8_bom(range<char>& to, codecvt_mode mode)
+  write_utf8_bom(range<C>& to, codecvt_mode mode)
   {
     if (mode & generate_header)
       return write_bom(to, utf8_bom);
@@ -218,8 +219,9 @@  namespace
   }
 
   // If consume_header is set in mode update from.next to after any BOM.
+  template<typename C>
   void
-  read_utf8_bom(range<const char>& from, codecvt_mode mode)
+  read_utf8_bom(range<const C>& from, codecvt_mode mode)
   {
     if (mode & consume_header)
       read_bom(from, utf8_bom);
@@ -245,8 +247,9 @@  namespace
   // Read a codepoint from a UTF-8 multibyte sequence.
   // Updates from.next if the codepoint is not greater than maxcode.
   // Returns invalid_mb_sequence, incomplete_mb_character or the code point.
+  template<typename C>
   char32_t
-  read_utf8_code_point(range<const char>& from, unsigned long maxcode)
+  read_utf8_code_point(range<const C>& from, unsigned long maxcode)
   {
     const size_t avail = from.size();
     if (avail == 0)
@@ -315,8 +318,9 @@  namespace
       return invalid_mb_sequence;
   }
 
+  template<typename C>
   bool
-  write_utf8_code_point(range<char>& to, char32_t code_point)
+  write_utf8_code_point(range<C>& to, char32_t code_point)
   {
     if (code_point < 0x80)
       {
@@ -445,8 +449,9 @@  namespace
   }
 
   // utf8 -> ucs4
+  template<typename C>
   codecvt_base::result
-  ucs4_in(range<const char>& from, range<char32_t>& to,
+  ucs4_in(range<const C>& from, range<char32_t>& to,
           unsigned long maxcode = max_code_point, codecvt_mode mode = {})
   {
     read_utf8_bom(from, mode);
@@ -463,8 +468,9 @@  namespace
   }
 
   // ucs4 -> utf8
+  template<typename C>
   codecvt_base::result
-  ucs4_out(range<const char32_t>& from, range<char>& to,
+  ucs4_out(range<const char32_t>& from, range<C>& to,
            unsigned long maxcode = max_code_point, codecvt_mode mode = {})
   {
     if (!write_utf8_bom(to, mode))
@@ -522,9 +528,9 @@  namespace
   enum class surrogates { allowed, disallowed };
 
   // utf8 -> utf16 (or utf8 -> ucs2 if s == surrogates::disallowed)
-  template<typename C>
+  template<typename C8, typename C16>
   codecvt_base::result
-  utf16_in(range<const char>& from, range<C>& to,
+  utf16_in(range<const C8>& from, range<C16>& to,
 	   unsigned long maxcode = max_code_point, codecvt_mode mode = {},
 	   surrogates s = surrogates::allowed)
   {
@@ -552,9 +558,9 @@  namespace
   }
 
   // utf16 -> utf8 (or ucs2 -> utf8 if s == surrogates::disallowed)
-  template<typename C>
+  template<typename C16, typename C8>
   codecvt_base::result
-  utf16_out(range<const C>& from, range<char>& to,
+  utf16_out(range<const C16>& from, range<C8>& to,
 	    unsigned long maxcode = max_code_point, codecvt_mode mode = {},
 	    surrogates s = surrogates::allowed)
   {
@@ -593,11 +599,12 @@  namespace
   }
 
   // return pos such that [begin,pos) is valid UTF-16 string no longer than max
-  const char*
-  utf16_span(const char* begin, const char* end, size_t max,
+  template<typename C>
+  const C*
+  utf16_span(const C* begin, const C* end, size_t max,
 	     char32_t maxcode = max_code_point, codecvt_mode mode = {})
   {
-    range<const char> from{ begin, end };
+    range<const C> from{ begin, end };
     read_utf8_bom(from, mode);
     size_t count = 0;
     while (count+1 < max)
@@ -615,8 +622,9 @@  namespace
   }
 
   // utf8 -> ucs2
+  template<typename C>
   codecvt_base::result
-  ucs2_in(range<const char>& from, range<char16_t>& to,
+  ucs2_in(range<const C>& from, range<char16_t>& to,
 	  char32_t maxcode = max_code_point, codecvt_mode mode = {})
   {
     // UCS-2 only supports characters in the BMP, i.e. one UTF-16 code unit:
@@ -625,8 +633,9 @@  namespace
   }
 
   // ucs2 -> utf8
+  template<typename C>
   codecvt_base::result
-  ucs2_out(range<const char16_t>& from, range<char>& to,
+  ucs2_out(range<const char16_t>& from, range<C>& to,
 	   char32_t maxcode = max_code_point, codecvt_mode mode = {})
   {
     // UCS-2 only supports characters in the BMP, i.e. one UTF-16 code unit:
@@ -687,11 +696,12 @@  namespace
     return reinterpret_cast<const char16_t*>(from.next);
   }
 
-  const char*
-  ucs2_span(const char* begin, const char* end, size_t max,
+  template<typename C>
+  const C*
+  ucs2_span(const C* begin, const C* end, size_t max,
             char32_t maxcode, codecvt_mode mode)
   {
-    range<const char> from{ begin, end };
+    range<const C> from{ begin, end };
     read_utf8_bom(from, mode);
     // UCS-2 only supports characters in the BMP, i.e. one UTF-16 code unit:
     maxcode = std::min(max_single_utf16_unit, maxcode);
@@ -702,11 +712,12 @@  namespace
   }
 
   // return pos such that [begin,pos) is valid UCS-4 string no longer than max
-  const char*
-  ucs4_span(const char* begin, const char* end, size_t max,
+  template<typename C>
+  const C*
+  ucs4_span(const C* begin, const C* end, size_t max,
             char32_t maxcode = max_code_point, codecvt_mode mode = {})
   {
-    range<const char> from{ begin, end };
+    range<const C> from{ begin, end };
     read_utf8_bom(from, mode);
     char32_t c = 0;
     while (max-- && c <= maxcode)
@@ -875,6 +886,156 @@  codecvt<char32_t, char, mbstate_t>::do_max_length() const throw()
   return 4;
 }
 
+#if defined(_GLIBCXX_USE_CHAR8_T)
+// Define members of codecvt<char16_t, char8_t, mbstate_t> specialization.
+// Converts from UTF-8 to UTF-16.
+
+locale::id codecvt<char16_t, char8_t, mbstate_t>::id;
+
+codecvt<char16_t, char8_t, mbstate_t>::~codecvt() { }
+
+codecvt_base::result
+codecvt<char16_t, char8_t, mbstate_t>::
+do_out(state_type&,
+       const intern_type* __from,
+       const intern_type* __from_end, const intern_type*& __from_next,
+       extern_type* __to, extern_type* __to_end,
+       extern_type*& __to_next) const
+{
+  range<const char16_t> from{ __from, __from_end };
+  range<char8_t> to{ __to, __to_end };
+  auto res = utf16_out(from, to);
+  __from_next = from.next;
+  __to_next = to.next;
+  return res;
+}
+
+codecvt_base::result
+codecvt<char16_t, char8_t, mbstate_t>::
+do_unshift(state_type&, extern_type* __to, extern_type*,
+	   extern_type*& __to_next) const
+{
+  __to_next = __to;
+  return noconv; // we don't use mbstate_t for the unicode facets
+}
+
+codecvt_base::result
+codecvt<char16_t, char8_t, mbstate_t>::
+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
+{
+  range<const char8_t> from{ __from, __from_end };
+  range<char16_t> to{ __to, __to_end };
+#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+  codecvt_mode mode = {};
+#else
+  codecvt_mode mode = little_endian;
+#endif
+  auto res = utf16_in(from, to, max_code_point, mode);
+  __from_next = from.next;
+  __to_next = to.next;
+  return res;
+}
+
+int
+codecvt<char16_t, char8_t, mbstate_t>::do_encoding() const throw()
+{ return 0; } // UTF-8 is not a fixed-width encoding
+
+bool
+codecvt<char16_t, char8_t, mbstate_t>::do_always_noconv() const throw()
+{ return false; }
+
+int
+codecvt<char16_t, char8_t, mbstate_t>::
+do_length(state_type&, const extern_type* __from,
+	  const extern_type* __end, size_t __max) const
+{
+  __end = utf16_span(__from, __end, __max);
+  return __end - __from;
+}
+
+int
+codecvt<char16_t, char8_t, mbstate_t>::do_max_length() const throw()
+{
+  // A single character (one or two UTF-16 code units) requires
+  // up to four UTF-8 code units.
+  return 4;
+}
+
+// Define members of codecvt<char32_t, char8_t, mbstate_t> specialization.
+// Converts from UTF-8 to UTF-32 (aka UCS-4).
+
+locale::id codecvt<char32_t, char8_t, mbstate_t>::id;
+
+codecvt<char32_t, char8_t, mbstate_t>::~codecvt() { }
+
+codecvt_base::result
+codecvt<char32_t, char8_t, mbstate_t>::
+do_out(state_type&, const intern_type* __from, const intern_type* __from_end,
+       const intern_type*& __from_next,
+       extern_type* __to, extern_type* __to_end,
+       extern_type*& __to_next) const
+{
+  range<const char32_t> from{ __from, __from_end };
+  range<char8_t> to{ __to, __to_end };
+  auto res = ucs4_out(from, to);
+  __from_next = from.next;
+  __to_next = to.next;
+  return res;
+}
+
+codecvt_base::result
+codecvt<char32_t, char8_t, mbstate_t>::
+do_unshift(state_type&, extern_type* __to, extern_type*,
+	   extern_type*& __to_next) const
+{
+  __to_next = __to;
+  return noconv;
+}
+
+codecvt_base::result
+codecvt<char32_t, char8_t, mbstate_t>::
+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
+{
+  range<const char8_t> from{ __from, __from_end };
+  range<char32_t> to{ __to, __to_end };
+  auto res = ucs4_in(from, to);
+  __from_next = from.next;
+  __to_next = to.next;
+  return res;
+}
+
+int
+codecvt<char32_t, char8_t, mbstate_t>::do_encoding() const throw()
+{ return 0; } // UTF-8 is not a fixed-width encoding
+
+bool
+codecvt<char32_t, char8_t, mbstate_t>::do_always_noconv() const throw()
+{ return false; }
+
+int
+codecvt<char32_t, char8_t, mbstate_t>::
+do_length(state_type&, const extern_type* __from,
+	  const extern_type* __end, size_t __max) const
+{
+  __end = ucs4_span(__from, __end, __max);
+  return __end - __from;
+}
+
+int
+codecvt<char32_t, char8_t, mbstate_t>::do_max_length() const throw()
+{
+  // A single character (one UTF-32 code unit) requires
+  // up to 4 UTF-8 code units.
+  return 4;
+}
+#endif // _GLIBCXX_USE_CHAR8_T
+
 // Define members of codecvt_utf8<char16_t> base class implementation.
 // Converts from UTF-8 to UCS-2.
 
@@ -1636,5 +1797,12 @@  inline template class __codecvt_abstract_base<char32_t, char, mbstate_t>;
 template class codecvt_byname<char16_t, char, mbstate_t>;
 template class codecvt_byname<char32_t, char, mbstate_t>;
 
+#if defined(_GLIBCXX_USE_CHAR8_T)
+inline template class __codecvt_abstract_base<char16_t, char8_t, mbstate_t>;
+inline template class __codecvt_abstract_base<char32_t, char8_t, mbstate_t>;
+template class codecvt_byname<char16_t, char8_t, mbstate_t>;
+template class codecvt_byname<char32_t, char8_t, mbstate_t>;
+#endif
+
 _GLIBCXX_END_NAMESPACE_VERSION
 }
diff --git a/libstdc++-v3/src/c++11/limits.cc b/libstdc++-v3/src/c++11/limits.cc
index 4d7889f2021..cfb3e5b027e 100644
--- a/libstdc++-v3/src/c++11/limits.cc
+++ b/libstdc++-v3/src/c++11/limits.cc
@@ -525,6 +525,33 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
   const bool numeric_limits<long double>::tinyness_before;
   const float_round_style numeric_limits<long double>::round_style;
 
+#ifdef _GLIBCXX_USE_CHAR8_T
+  // char8_t
+  const bool numeric_limits<char8_t>::is_specialized;
+  const int  numeric_limits<char8_t>::digits;
+  const int  numeric_limits<char8_t>::digits10;
+  const int  numeric_limits<char8_t>::max_digits10;
+  const bool numeric_limits<char8_t>::is_signed;
+  const bool numeric_limits<char8_t>::is_integer;
+  const bool numeric_limits<char8_t>::is_exact;
+  const int  numeric_limits<char8_t>::radix;
+  const int  numeric_limits<char8_t>::min_exponent;
+  const int  numeric_limits<char8_t>::min_exponent10;
+  const int  numeric_limits<char8_t>::max_exponent;
+  const int  numeric_limits<char8_t>::max_exponent10;
+  const bool numeric_limits<char8_t>::has_infinity;
+  const bool numeric_limits<char8_t>::has_quiet_NaN;
+  const bool numeric_limits<char8_t>::has_signaling_NaN;
+  const float_denorm_style numeric_limits<char8_t>::has_denorm;
+  const bool numeric_limits<char8_t>::has_denorm_loss;
+  const bool numeric_limits<char8_t>::is_iec559;
+  const bool numeric_limits<char8_t>::is_bounded;
+  const bool numeric_limits<char8_t>::is_modulo;
+  const bool numeric_limits<char8_t>::traps;
+  const bool numeric_limits<char8_t>::tinyness_before;
+  const float_round_style numeric_limits<char8_t>::round_style;
+#endif // _GLIBCXX_USE_CHAR8_T
+
   // char16_t
   const bool numeric_limits<char16_t>::is_specialized;
   const int  numeric_limits<char16_t>::digits;
diff --git a/libstdc++-v3/src/c++98/Makefile.am b/libstdc++-v3/src/c++98/Makefile.am
index bceaa5b0f40..3545ebbac1b 100644
--- a/libstdc++-v3/src/c++98/Makefile.am
+++ b/libstdc++-v3/src/c++98/Makefile.am
@@ -184,13 +184,13 @@  endif
 
 # XXX TODO move locale_init.cc and localename.cc to src/c++11
 locale_init.lo: locale_init.cc
-	$(LTCXXCOMPILE) -std=gnu++11 -c $<
+	$(LTCXXCOMPILE) -std=gnu++11 -fchar8_t -c $<
 locale_init.o: locale_init.cc
-	$(LTCXXCOMPILE) -std=gnu++11 -c $<
+	$(LTCXXCOMPILE) -std=gnu++11 -fchar8_t -c $<
 localename.lo: localename.cc
-	$(LTCXXCOMPILE) -std=gnu++11 -c $<
+	$(LTCXXCOMPILE) -std=gnu++11 -fchar8_t -c $<
 localename.o: localename.cc
-	$(LTCXXCOMPILE) -std=gnu++11 -c $<
+	$(LTCXXCOMPILE) -std=gnu++11 -fchar8_t -c $<
 
 # Use special rules for the deprecated source files so that they find
 # deprecated include files.
diff --git a/libstdc++-v3/src/c++98/Makefile.in b/libstdc++-v3/src/c++98/Makefile.in
index 33f2ac0f87a..53c8592a6cd 100644
--- a/libstdc++-v3/src/c++98/Makefile.in
+++ b/libstdc++-v3/src/c++98/Makefile.in
@@ -805,13 +805,13 @@  c++locale.o: c++locale.cc
 
 # XXX TODO move locale_init.cc and localename.cc to src/c++11
 locale_init.lo: locale_init.cc
-	$(LTCXXCOMPILE) -std=gnu++11 -c $<
+	$(LTCXXCOMPILE) -std=gnu++11 -fchar8_t -c $<
 locale_init.o: locale_init.cc
-	$(LTCXXCOMPILE) -std=gnu++11 -c $<
+	$(LTCXXCOMPILE) -std=gnu++11 -fchar8_t -c $<
 localename.lo: localename.cc
-	$(LTCXXCOMPILE) -std=gnu++11 -c $<
+	$(LTCXXCOMPILE) -std=gnu++11 -fchar8_t -c $<
 localename.o: localename.cc
-	$(LTCXXCOMPILE) -std=gnu++11 -c $<
+	$(LTCXXCOMPILE) -std=gnu++11 -fchar8_t -c $<
 strstream.lo: strstream.cc
 	$(LTCXXCOMPILE) -I$(GLIBCXX_INCLUDE_DIR)/backward -Wno-deprecated -c $<
 strstream.o: strstream.cc
diff --git a/libstdc++-v3/src/c++98/locale_init.cc b/libstdc++-v3/src/c++98/locale_init.cc
index b580a9f9d58..edf4ca8fd8e 100644
--- a/libstdc++-v3/src/c++98/locale_init.cc
+++ b/libstdc++-v3/src/c++98/locale_init.cc
@@ -209,6 +209,16 @@  namespace
   __attribute__ ((aligned(__alignof__(codecvt<char32_t, char, mbstate_t>))));
   fake_codecvt_c32 codecvt_c32;
 
+#ifdef _GLIBCXX_USE_CHAR8_T
+  typedef char fake_codecvt_c16_c8[sizeof(codecvt<char16_t, char8_t, mbstate_t>)]
+  __attribute__ ((aligned(__alignof__(codecvt<char16_t, char8_t, mbstate_t>))));
+  fake_codecvt_c16_c8 codecvt_c16_c8;
+
+  typedef char fake_codecvt_c32_c8[sizeof(codecvt<char32_t, char8_t, mbstate_t>)]
+  __attribute__ ((aligned(__alignof__(codecvt<char32_t, char8_t, mbstate_t>))));
+  fake_codecvt_c32_c8 codecvt_c32_c8;
+#endif
+
   // Storage for "C" locale caches.
   typedef char fake_num_cache_c[sizeof(std::__numpunct_cache<char>)]
   __attribute__ ((aligned(__alignof__(std::__numpunct_cache<char>))));
@@ -329,6 +339,10 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #if _GLIBCXX_NUM_UNICODE_FACETS != 0
     &codecvt<char16_t, char, mbstate_t>::id,
     &codecvt<char32_t, char, mbstate_t>::id,
+#ifdef _GLIBCXX_USE_CHAR8_T
+    &codecvt<char16_t, char8_t, mbstate_t>::id,
+    &codecvt<char32_t, char8_t, mbstate_t>::id,
+#endif
 #endif
     0
   };
@@ -536,6 +550,12 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #if _GLIBCXX_NUM_UNICODE_FACETS != 0
     _M_init_facet(new (&codecvt_c16) codecvt<char16_t, char, mbstate_t>(1));
     _M_init_facet(new (&codecvt_c32) codecvt<char32_t, char, mbstate_t>(1));
+
+#ifdef _GLIBCXX_USE_CHAR8_T
+    _M_init_facet(new (&codecvt_c16_c8) codecvt<char16_t, char8_t, mbstate_t>(1));
+    _M_init_facet(new (&codecvt_c32_c8) codecvt<char32_t, char8_t, mbstate_t>(1));
+#endif
+
 #endif
 
 #if _GLIBCXX_USE_DUAL_ABI
diff --git a/libstdc++-v3/src/c++98/localename.cc b/libstdc++-v3/src/c++98/localename.cc
index afb43e5cea9..aa66ae207a3 100644
--- a/libstdc++-v3/src/c++98/localename.cc
+++ b/libstdc++-v3/src/c++98/localename.cc
@@ -272,6 +272,12 @@  const int num_facets = _GLIBCXX_NUM_FACETS + _GLIBCXX_NUM_UNICODE_FACETS
 #if _GLIBCXX_NUM_UNICODE_FACETS != 0
         _M_init_facet(new codecvt<char16_t, char, mbstate_t>);
         _M_init_facet(new codecvt<char32_t, char, mbstate_t>);
+
+#ifdef _GLIBCXX_USE_CHAR8_T
+        _M_init_facet(new codecvt<char16_t, char8_t, mbstate_t>);
+        _M_init_facet(new codecvt<char32_t, char8_t, mbstate_t>);
+#endif
+
 #endif
 
 #if _GLIBCXX_USE_DUAL_ABI
diff --git a/libstdc++-v3/testsuite/util/testsuite_abi.cc b/libstdc++-v3/testsuite/util/testsuite_abi.cc
index c9aaf74133f..f45bcf46fac 100644
--- a/libstdc++-v3/testsuite/util/testsuite_abi.cc
+++ b/libstdc++-v3/testsuite/util/testsuite_abi.cc
@@ -220,6 +220,7 @@  check_version(symbol& test, bool added)
       known_versions.push_back("CXXABI_1.3.9");
       known_versions.push_back("CXXABI_1.3.10");
       known_versions.push_back("CXXABI_1.3.11");
+      known_versions.push_back("CXXABI_1.3.12");
       known_versions.push_back("CXXABI_TM_1");
       known_versions.push_back("CXXABI_FLOAT128");
     }
@@ -238,7 +239,7 @@  check_version(symbol& test, bool added)
 
       // Check that added symbols are added in the latest pre-release version.
       bool latestp = (test.version_name == "GLIBCXX_3.4.26"
-		     || test.version_name == "CXXABI_1.3.11"
+		     || test.version_name == "CXXABI_1.3.12"
 		     || test.version_name == "CXXABI_FLOAT128"
 		     || test.version_name == "CXXABI_TM_1");
       if (added && !latestp)