Hi!

The following patch attempts to implement the
C++26 P3378R2 - constexpr exception types
paper.
This is quite complicated, because most of these classes which should
be constexpr-ized use solely or mostly out of line definitions in
libstdc++, both for historical, code size and dual ABI reasons, so that
one can throw these as exceptions between TUs with old vs. new (or vice
versa) ABIs.
For this reason, logic_error/runtime_error and classes derived from it
have the old ABI std::string object inside of them and the exported
APIs from libstdc++.so.6 ensure the right thing.

Now, because new invoked during constant evaluation needs to be deleted
during the same constant evaluation and can't leak into the constant
expressions, I think we don't have to use COW strings under the hood
(which aren't constexpr I guess because of reference counting/COW) and
we can use something else, the patch uses heap allocated std::string
object (where __cow_constexpr_string class has just a pointer to that).
As I think we still want to hide the ugly details if !consteval in the
library, the patch exports 8 __cow_string class symbols (6 existing which
were previously just not exported and 2 new ones) and if !consteval
calls those through extern "C" _Zmangled_name symbols.  The functions
are always_inline.

And then logic_error etc. have for C++26 (precisely for
__cpp_lib_constexpr_exceptions >= 202502L) constexpr definitions of
cdtors/methods.  This results in slightly larger code (a few insns at most)
at runtime for C++26, e.g. instead of calling say some logic error
cdtor/method with 2 arguments it calls some __cow_string one with 2
arguments but + 8 bytes pointer additions on both.

The only unfinished part in the patch is <format>.  bits/formatfwd.h
has
/// @cond undocumented
  [[noreturn]]
  inline void
  __throw_format_error(const char* __what);
while when I added _GLIBCXX_CONSTEXPR_FORMAT_ERROR to the <format>
copy of those declarations/definitions I obviously got errors because
of mismatch between the bits/formatfwd.h declaration and the definition.
And I'm afraid some of the headers which call __throw_format_error don't
include <format>.  So perhaps format_error needs to be moved to
bits/formatfwd.h or something.  Or have __throw_format_error which is
not constexpr and some other named function which is constexpr?  Or when
we want constexpr just do the throw instead of calling __throw_format_error?
Some of the __throw_format_error callers certainly aren't constexpr, others
are.

So far lightly tested with
GLIBCXX_TESTSUITE_STDS=98,11,17,23,26 make check 
RUNTESTFLAGS="conformance.exp='18_support/exception/* 
19_diagnostics/runtime_error/* 19_diagnostics/logic_error/* 
19_diagnostics/headers/stdexcept/* 20_util/expected/* 20_util/variant/* 
20_util/optional/*'"

2025-07-16  Jakub Jelinek  <ja...@redhat.com>

        * include/bits/version.def: Implement C++26 P3378R2 - constexpr
        exception types.
        (constexpr_exceptions): Change value from 202411 to 202502.
        * include/bits/version.h: Regenerate.
        * src/c++11/cow-stdexcept.cc (__cow_string(const char*)): New
        ctor.
        (__cow_string::c_str()): New method.
        * config/abi/pre/gnu.ver (GLIBCXX_3.4.35): Export 8 __cow_string
        symbols.
        * include/std/stdexcept (__cow_constexpr_string): New class if
        __cpp_lib_constexpr_exceptions >= 202502L.
        (__cow_string): In that case typedef to __cow_constexpr_string.
        (logic_error, domain_error, invalid_argument, length_error,
        out_of_range, runtime_error, range_error, overflow_error,
        underflow_error): If __cpp_lib_constexpr_exceptions >= 202502L
        make all cdtors and methods constexpr.
        * include/std/optional (__glibcxx_want_constexpr_exceptions): Define
        before including bits/version.h.
        (bad_optional_access::what): Make constexpr for
        __cpp_lib_constexpr_exceptions >= 202502L.
        (__throw_bad_optional_access): Likewise.
        * include/std/expected (__glibcxx_want_constexpr_exceptions): Define
        before including bits/version.h.
        (bad_expected_access): Make cdtors and all methods constexpr for
        __cpp_lib_constexpr_exceptions >= 202502L.
        * include/std/format (__glibcxx_want_constexpr_exceptions): Define
        before including bits/version.h.
        (_GLIBCXX_CONSTEXPR_FORMAT_ERROR): Define and undef later.
        (format_error): Use _GLIBCXX_CONSTEXPR_FORMAT_ERROR on ctors.
        * include/std/variant (__glibcxx_want_constexpr_exceptions): Define
        before including bits/version.h.
        (_GLIBCXX_CONSTEXPR_BAD_VARIANT_ACCESS): Define and undef later.
        (bad_variant_access): Use it on ctors and what() method.
        (__throw_bad_variant_access): Use it here too.
        * testsuite/18_support/exception/version.cc: Adjust expected
        __cpp_lib_constexpr_exceptions value.
        * testsuite/19_diagnostics/runtime_error/constexpr.cc: New test.
        * testsuite/19_diagnostics/headers/stdexcept/version.cc: New test.
        * testsuite/19_diagnostics/logic_error/constexpr.cc: New test.
        * testsuite/20_util/expected/observers.cc (test_value_throw): Change
        return type to bool from void, return true at the end, add test
        to dereference what() first character.  Make it constexpr for
        __cpp_lib_constexpr_exceptions >= 202502L and add static_assert.
        * testsuite/20_util/expected/version.cc: Add tests for
        __cpp_lib_constexpr_exceptions value.
        * testsuite/20_util/variant/constexpr.cc: For
        __cpp_lib_constexpr_exceptions >= 202502L include <string>.
        (test_get): New function if __cpp_lib_constexpr_exceptions >= 202502L,
        assert calling it is true.
        * testsuite/20_util/variant/version.cc: Add tests for
        __cpp_lib_constexpr_exceptions value.
        * testsuite/20_util/optional/constexpr/observers/3.cc: Include
        testsuite_hooks.h.
        (eat, test01): New functions.  Assert test01() is true.
        * testsuite/20_util/optional/version.cc: Add tests for
        __cpp_lib_constexpr_exceptions value.

--- libstdc++-v3/include/bits/version.def.jj    2025-07-15 14:49:29.973515451 
+0200
+++ libstdc++-v3/include/bits/version.def       2025-07-16 07:06:05.645224306 
+0200
@@ -2053,7 +2053,7 @@ ftms = {
 ftms = {
   name = constexpr_exceptions;
   values = {
-    v = 202411;
+    v = 202502;
     cxxmin = 26;
     extra_cond = "__cpp_constexpr_exceptions >= 202411L";
   };
--- libstdc++-v3/include/bits/version.h.jj      2025-07-15 14:49:29.973515451 
+0200
+++ libstdc++-v3/include/bits/version.h 2025-07-16 07:06:14.934235823 +0200
@@ -2301,9 +2301,9 @@
 
 #if !defined(__cpp_lib_constexpr_exceptions)
 # if (__cplusplus >  202302L) && (__cpp_constexpr_exceptions >= 202411L)
-#  define __glibcxx_constexpr_exceptions 202411L
+#  define __glibcxx_constexpr_exceptions 202502L
 #  if defined(__glibcxx_want_all) || 
defined(__glibcxx_want_constexpr_exceptions)
-#   define __cpp_lib_constexpr_exceptions 202411L
+#   define __cpp_lib_constexpr_exceptions 202502L
 #  endif
 # endif
 #endif /* !defined(__cpp_lib_constexpr_exceptions) && 
defined(__glibcxx_want_constexpr_exceptions) */
--- libstdc++-v3/src/c++11/cow-stdexcept.cc.jj  2025-01-02 20:54:32.928118861 
+0100
+++ libstdc++-v3/src/c++11/cow-stdexcept.cc     2025-07-16 06:46:44.893573401 
+0200
@@ -126,18 +126,22 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
     __cow_string();
     __cow_string(const std::string& s);
+    __cow_string(const char*);
     __cow_string(const char*, size_t n);
     __cow_string(const __cow_string&) noexcept;
     __cow_string& operator=(const __cow_string&) noexcept;
     ~__cow_string();
     __cow_string(__cow_string&&) noexcept;
     __cow_string& operator=(__cow_string&&) noexcept;
+    const char* c_str() const noexcept;
   };
 
   __cow_string::__cow_string() : _M_str() { }
 
   __cow_string::__cow_string(const std::string& s) : _M_str(s) { }
 
+  __cow_string::__cow_string(const char* s) : _M_str(s) { }
+
   __cow_string::__cow_string(const char* s, size_t n) : _M_str(s, n) { }
 
   __cow_string::__cow_string(const __cow_string& s) noexcept
@@ -162,6 +166,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     return *this;
   }
 
+  const char*
+  __cow_string::c_str() const noexcept
+  {
+    return _M_str.c_str();
+  }
+
   static_assert(sizeof(__cow_string) == sizeof(std::string),
                 "sizeof(std::string) has changed");
   static_assert(alignof(__cow_string) == alignof(std::string),
--- libstdc++-v3/config/abi/pre/gnu.ver.jj      2025-07-09 20:38:59.044628012 
+0200
+++ libstdc++-v3/config/abi/pre/gnu.ver 2025-07-16 06:53:04.966552241 +0200
@@ -2569,6 +2569,16 @@ GLIBCXX_3.4.35 {
     
_ZN11__gnu_debug25_Safe_local_iterator_base16_M_attach_singleEPKNS_30_Safe_unordered_container_baseEb;
     _ZNK11__gnu_debug30_Safe_unordered_container_base13_M_detach_allEv;
     _ZNK11__gnu_debug30_Safe_unordered_container_base7_M_swapERKS0_;
+
+    # std::__cow_string
+    _ZNSt12__cow_stringC2EPKc;
+    _ZNSt12__cow_stringC2EPKc[jmy];
+    _ZNSt12__cow_stringC2ERKS_;
+    _ZNSt12__cow_stringC2EOS_;
+    _ZNSt12__cow_stringD2Ev;
+    _ZNSt12__cow_stringaSERKS_;
+    _ZNSt12__cow_stringaSEOS_;
+    _ZNKSt12__cow_string5c_strEv;
 } GLIBCXX_3.4.34;
 
 # Symbols in the support library (libsupc++) have their own tag.
--- libstdc++-v3/include/std/stdexcept.jj       2025-01-02 20:54:32.913119069 
+0100
+++ libstdc++-v3/include/std/stdexcept  2025-07-16 08:40:53.227245914 +0200
@@ -46,6 +46,153 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
 #if _GLIBCXX_USE_DUAL_ABI
 #if _GLIBCXX_USE_CXX11_ABI
+#if __cpp_lib_constexpr_exceptions >= 202502L
+  struct __cow_constexpr_string;
+  namespace __detail
+  {
+    extern "C"
+    {
+      void _ZNSt12__cow_stringC2EPKcm(__cow_constexpr_string*, const char*,
+                                     unsigned long);
+      void _ZNSt12__cow_stringC2EPKcj(__cow_constexpr_string*, const char*,
+                                     unsigned int);
+      void _ZNSt12__cow_stringC2EPKcy(__cow_constexpr_string*, const char*,
+                                     unsigned long long);
+      void _ZNSt12__cow_stringC2EPKc(__cow_constexpr_string*, const char*);
+      void _ZNSt12__cow_stringC2ERKS_(__cow_constexpr_string*,
+                                     const __cow_constexpr_string&) noexcept;
+      void _ZNSt12__cow_stringC2EOS_(__cow_constexpr_string*,
+                                    __cow_constexpr_string&&) noexcept;
+      void _ZNSt12__cow_stringD2Ev(__cow_constexpr_string*);
+      __cow_constexpr_string&
+      _ZNSt12__cow_stringaSERKS_(__cow_constexpr_string*,
+                                const __cow_constexpr_string&) noexcept;
+      __cow_constexpr_string&
+      _ZNSt12__cow_stringaSEOS_(__cow_constexpr_string*,
+                               __cow_constexpr_string&&) noexcept;
+      const char*
+      _ZNKSt12__cow_string5c_strEv(const __cow_constexpr_string*) noexcept;
+    }
+  } // namespace __detail
+
+  // Emulates an old COW string when the new std::string is in use,
+  // but in addition is constexpr and uses the __cow_string out of
+  // line cdtors/methods unless manifestly constant evaluated.
+  struct __cow_constexpr_string
+  {
+    union {
+      const char* _M_p;
+      char _M_bytes[sizeof(const char*)];
+      string* _M_str;
+    };
+
+    [[__gnu__::__always_inline__]] constexpr
+    __cow_constexpr_string(const string& __o)
+    {
+      if consteval {
+       _M_str = new string(__o);
+      } else {
+       __cow_constexpr_string_ctor(__o.c_str(), __o.length());
+      }
+    }
+
+    [[__gnu__::__always_inline__]] inline void
+    __cow_constexpr_string_ctor(const char *__s, unsigned long __l)
+    {
+      __detail::_ZNSt12__cow_stringC2EPKcm(this, __s, __l);
+    }
+
+    [[__gnu__::__always_inline__]] inline void
+    __cow_constexpr_string_ctor(const char *__s, unsigned int __l)
+    {
+      __detail::_ZNSt12__cow_stringC2EPKcj(this, __s, __l);
+    }
+
+    [[__gnu__::__always_inline__]] inline void
+    __cow_constexpr_string_ctor(const char *__s, unsigned long long __l)
+    {
+      __detail::_ZNSt12__cow_stringC2EPKcy(this, __s, __l);
+    }
+
+    [[__gnu__::__always_inline__]] constexpr
+    __cow_constexpr_string(const char* __o)
+    {
+      if consteval {
+       _M_str = new string(__o);
+      } else {
+       __detail::_ZNSt12__cow_stringC2EPKc(this, __o);
+      }
+    }
+
+    [[__gnu__::__always_inline__]] constexpr
+    __cow_constexpr_string(const __cow_constexpr_string& __o) noexcept
+    {
+      if consteval {
+       _M_str = new string(*__o._M_str);
+      } else {
+       __detail::_ZNSt12__cow_stringC2ERKS_(this, __o);
+      }
+    }
+
+    [[__gnu__::__always_inline__]] constexpr __cow_constexpr_string&
+    operator=(const __cow_constexpr_string& __o) noexcept
+    {
+      if consteval {
+       string* __p = _M_str;
+       _M_str = new string(*__o._M_str);
+       delete __p;
+       return *this;
+      } else {
+       return __detail::_ZNSt12__cow_stringaSERKS_(this, __o);
+      }
+    }
+
+    [[__gnu__::__always_inline__]] constexpr
+    ~__cow_constexpr_string()
+    {
+      if consteval {
+       delete _M_str;
+      } else {
+       __detail::_ZNSt12__cow_stringD2Ev(this);
+      }
+    }
+
+    [[__gnu__::__always_inline__]] constexpr
+    __cow_constexpr_string(__cow_constexpr_string&& __o) noexcept
+    {
+      if consteval {
+       _M_str = new string(std::move(*__o._M_str));
+      } else {
+       __detail::_ZNSt12__cow_stringC2EOS_(this, std::move(__o));
+      }
+    }
+
+    [[__gnu__::__always_inline__]] constexpr __cow_constexpr_string&
+    operator=(__cow_constexpr_string&& __o) noexcept
+    {
+      if consteval {
+       string* __p = _M_str;
+       _M_str = new string(std::move(*__o._M_str));
+       delete __p;
+       return *this;
+      } else {
+       return __detail::_ZNSt12__cow_stringaSEOS_(this, std::move(__o));
+      }        
+    }
+
+    [[__gnu__::__always_inline__]] constexpr const char*
+    c_str() const noexcept
+    {
+      if consteval {
+       return _M_str->c_str();
+      } else {
+       return __detail::_ZNKSt12__cow_string5c_strEv(this);
+      }
+    }
+  };
+
+  typedef __cow_constexpr_string __cow_string;
+#else
   // Emulates an old COW string when the new std::string is in use.
   struct __cow_string
   {
@@ -65,6 +212,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     __cow_string& operator=(__cow_string&&) noexcept;
 #endif
   };
+#endif
 
   typedef basic_string<char> __sso_string;
 #else // _GLIBCXX_USE_CXX11_ABI
@@ -117,6 +265,28 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     __cow_string _M_msg;
 
   public:
+#if __cpp_lib_constexpr_exceptions >= 202502L
+    constexpr explicit
+    logic_error(const string& __arg) _GLIBCXX_TXN_SAFE
+    : _M_msg(__arg) {}
+
+    constexpr explicit
+    logic_error(const char* __arg) _GLIBCXX_TXN_SAFE
+    : _M_msg(__arg) {}
+
+    constexpr logic_error(logic_error&& __arg) noexcept = default;
+    constexpr logic_error& operator=(logic_error&& __arg) noexcept = default;
+    constexpr logic_error(const logic_error&) noexcept = default;
+    constexpr logic_error& operator=(const logic_error&) noexcept = default;
+
+    constexpr virtual ~logic_error() _GLIBCXX_TXN_SAFE_DYN noexcept { }
+
+    constexpr virtual const char*
+    what() const _GLIBCXX_TXN_SAFE_DYN noexcept
+    {
+      return _M_msg.c_str();
+    }
+#else
     /** Takes a character string describing the error.  */
     explicit
     logic_error(const string& __arg) _GLIBCXX_TXN_SAFE;
@@ -143,6 +313,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
      *  the current error (the same string passed to the ctor).  */
     virtual const char*
     what() const _GLIBCXX_TXN_SAFE_DYN _GLIBCXX_NOTHROW;
+#endif
 
 # ifdef _GLIBCXX_TM_TS_INTERNAL
     friend void*
@@ -155,6 +326,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   class domain_error : public logic_error
   {
   public:
+#if __cpp_lib_constexpr_exceptions >= 202502L
+    constexpr explicit domain_error(const string& __arg) _GLIBCXX_TXN_SAFE
+    : logic_error(__arg) { }
+    constexpr explicit domain_error(const char* __arg) _GLIBCXX_TXN_SAFE
+    : logic_error(__arg) { }
+    constexpr domain_error(const domain_error&) = default;
+    constexpr domain_error& operator=(const domain_error&) = default;
+    constexpr domain_error(domain_error&&) = default;
+    constexpr domain_error& operator=(domain_error&&) = default;
+    constexpr virtual ~domain_error() _GLIBCXX_NOTHROW { }
+#else
     explicit domain_error(const string& __arg) _GLIBCXX_TXN_SAFE;
 #if __cplusplus >= 201103L
     explicit domain_error(const char*) _GLIBCXX_TXN_SAFE;
@@ -164,12 +346,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     domain_error& operator=(domain_error&&) = default;
 #endif
     virtual ~domain_error() _GLIBCXX_NOTHROW;
+#endif
   };
 
   /** Thrown to report invalid arguments to functions.  */
   class invalid_argument : public logic_error
   {
   public:
+#if __cpp_lib_constexpr_exceptions >= 202502L
+    constexpr explicit invalid_argument(const string& __arg) _GLIBCXX_TXN_SAFE
+    : logic_error(__arg) { }
+    constexpr explicit invalid_argument(const char* __arg) _GLIBCXX_TXN_SAFE
+    : logic_error(__arg) { }
+    constexpr invalid_argument(const invalid_argument&) = default;
+    constexpr invalid_argument& operator=(const invalid_argument&) = default;
+    constexpr invalid_argument(invalid_argument&&) = default;
+    constexpr invalid_argument& operator=(invalid_argument&&) = default;
+    constexpr virtual ~invalid_argument() _GLIBCXX_NOTHROW { }
+#else
     explicit invalid_argument(const string& __arg) _GLIBCXX_TXN_SAFE;
 #if __cplusplus >= 201103L
     explicit invalid_argument(const char*) _GLIBCXX_TXN_SAFE;
@@ -179,6 +373,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     invalid_argument& operator=(invalid_argument&&) = default;
 #endif
     virtual ~invalid_argument() _GLIBCXX_NOTHROW;
+#endif
   };
 
   /** Thrown when an object is constructed that would exceed its maximum
@@ -186,6 +381,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   class length_error : public logic_error
   {
   public:
+#if __cpp_lib_constexpr_exceptions >= 202502L
+    constexpr explicit length_error(const string& __arg) _GLIBCXX_TXN_SAFE
+    : logic_error(__arg) { }
+    constexpr explicit length_error(const char* __arg) _GLIBCXX_TXN_SAFE
+    : logic_error(__arg) { }
+    constexpr length_error(const length_error&) = default;
+    constexpr length_error& operator=(const length_error&) = default;
+    constexpr length_error(length_error&&) = default;
+    constexpr length_error& operator=(length_error&&) = default;
+    constexpr virtual ~length_error() _GLIBCXX_NOTHROW { }
+#else
     explicit length_error(const string& __arg) _GLIBCXX_TXN_SAFE;
 #if __cplusplus >= 201103L
     explicit length_error(const char*) _GLIBCXX_TXN_SAFE;
@@ -195,6 +401,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     length_error& operator=(length_error&&) = default;
 #endif
     virtual ~length_error() _GLIBCXX_NOTHROW;
+#endif
   };
 
   /** This represents an argument whose value is not within the expected
@@ -202,6 +409,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   class out_of_range : public logic_error
   {
   public:
+#if __cpp_lib_constexpr_exceptions >= 202502L
+    constexpr explicit out_of_range(const string& __arg) _GLIBCXX_TXN_SAFE
+    : logic_error(__arg) { }
+    constexpr explicit out_of_range(const char* __arg) _GLIBCXX_TXN_SAFE
+    : logic_error(__arg) { }
+    constexpr out_of_range(const out_of_range&) = default;
+    constexpr out_of_range& operator=(const out_of_range&) = default;
+    constexpr out_of_range(out_of_range&&) = default;
+    constexpr out_of_range& operator=(out_of_range&&) = default;
+    constexpr virtual ~out_of_range() _GLIBCXX_NOTHROW { }
+#else
     explicit out_of_range(const string& __arg) _GLIBCXX_TXN_SAFE;
 #if __cplusplus >= 201103L
     explicit out_of_range(const char*) _GLIBCXX_TXN_SAFE;
@@ -211,6 +429,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     out_of_range& operator=(out_of_range&&) = default;
 #endif
     virtual ~out_of_range() _GLIBCXX_NOTHROW;
+#endif
   };
 
   /** Runtime errors represent problems outside the scope of a program;
@@ -223,6 +442,28 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     __cow_string _M_msg;
 
   public:
+#if __cpp_lib_constexpr_exceptions >= 202502L
+    constexpr explicit
+    runtime_error(const string& __arg) _GLIBCXX_TXN_SAFE
+    : _M_msg(__arg) {}
+
+    constexpr explicit
+    runtime_error(const char* __arg) _GLIBCXX_TXN_SAFE
+    : _M_msg(__arg) {}
+
+    constexpr runtime_error(runtime_error&&) noexcept = default;
+    constexpr runtime_error& operator=(runtime_error&&) noexcept = default;
+    constexpr runtime_error(const runtime_error&) noexcept = default;
+    runtime_error& operator=(const runtime_error&) noexcept = default;
+
+    constexpr virtual ~runtime_error() _GLIBCXX_TXN_SAFE_DYN noexcept { }
+
+    constexpr virtual const char*
+    what() const _GLIBCXX_TXN_SAFE_DYN noexcept
+    {
+      return _M_msg.c_str();
+    }
+#else
     /** Takes a character string describing the error.  */
     explicit
     runtime_error(const string& __arg) _GLIBCXX_TXN_SAFE;
@@ -249,6 +490,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
      *  the current error (the same string passed to the ctor).  */
     virtual const char*
     what() const _GLIBCXX_TXN_SAFE_DYN _GLIBCXX_NOTHROW;
+#endif
 
 # ifdef _GLIBCXX_TM_TS_INTERNAL
     friend void*
@@ -260,6 +502,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   class range_error : public runtime_error
   {
   public:
+#if __cpp_lib_constexpr_exceptions >= 202502L
+    constexpr explicit range_error(const string& __arg) _GLIBCXX_TXN_SAFE
+    : runtime_error(__arg) { }
+    constexpr explicit range_error(const char* __arg) _GLIBCXX_TXN_SAFE
+    : runtime_error(__arg) { }
+    constexpr range_error(const range_error&) = default;
+    constexpr range_error& operator=(const range_error&) = default;
+    constexpr range_error(range_error&&) = default;
+    constexpr range_error& operator=(range_error&&) = default;
+    constexpr virtual ~range_error() noexcept { }
+#else
     explicit range_error(const string& __arg) _GLIBCXX_TXN_SAFE;
 #if __cplusplus >= 201103L
     explicit range_error(const char*) _GLIBCXX_TXN_SAFE;
@@ -269,12 +522,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     range_error& operator=(range_error&&) = default;
 #endif
     virtual ~range_error() _GLIBCXX_NOTHROW;
+#endif
   };
 
   /** Thrown to indicate arithmetic overflow.  */
   class overflow_error : public runtime_error
   {
   public:
+#if __cpp_lib_constexpr_exceptions >= 202502L
+    constexpr explicit overflow_error(const string& __arg) _GLIBCXX_TXN_SAFE
+    : runtime_error(__arg) { }
+    constexpr explicit overflow_error(const char* __arg) _GLIBCXX_TXN_SAFE
+    : runtime_error(__arg) { }
+    constexpr overflow_error(const overflow_error&) = default;
+    constexpr overflow_error& operator=(const overflow_error&) = default;
+    constexpr overflow_error(overflow_error&&) = default;
+    constexpr overflow_error& operator=(overflow_error&&) = default;
+    constexpr virtual ~overflow_error() noexcept { }
+#else
     explicit overflow_error(const string& __arg) _GLIBCXX_TXN_SAFE;
 #if __cplusplus >= 201103L
     explicit overflow_error(const char*) _GLIBCXX_TXN_SAFE;
@@ -284,12 +549,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     overflow_error& operator=(overflow_error&&) = default;
 #endif
     virtual ~overflow_error() _GLIBCXX_NOTHROW;
+#endif
   };
 
   /** Thrown to indicate arithmetic underflow.  */
   class underflow_error : public runtime_error
   {
   public:
+#if __cpp_lib_constexpr_exceptions >= 202502L
+    constexpr explicit underflow_error(const string& __arg) _GLIBCXX_TXN_SAFE
+    : runtime_error(__arg) { }
+    constexpr explicit underflow_error(const char* __arg) _GLIBCXX_TXN_SAFE
+    : runtime_error(__arg) { }
+    constexpr underflow_error(const underflow_error&) = default;
+    constexpr underflow_error& operator=(const underflow_error&) = default;
+    constexpr underflow_error(underflow_error&&) = default;
+    constexpr underflow_error& operator=(underflow_error&&) = default;
+    constexpr virtual ~underflow_error() noexcept { }
+#else
     explicit underflow_error(const string& __arg) _GLIBCXX_TXN_SAFE;
 #if __cplusplus >= 201103L
     explicit underflow_error(const char*) _GLIBCXX_TXN_SAFE;
@@ -299,6 +576,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     underflow_error& operator=(underflow_error&&) = default;
 #endif
     virtual ~underflow_error() _GLIBCXX_NOTHROW;
+#endif
   };
 
   /// @} group exceptions
--- libstdc++-v3/include/std/optional.jj        2025-07-15 14:49:29.975515425 
+0200
+++ libstdc++-v3/include/std/optional   2025-07-16 09:14:51.687298084 +0200
@@ -38,6 +38,7 @@
 #define __glibcxx_want_optional
 #define __glibcxx_want_optional_range_support
 #define __glibcxx_want_constrained_equality
+#define __glibcxx_want_constexpr_exceptions
 #include <bits/version.h>
 
 #ifdef __cpp_lib_optional // C++ >= 17
@@ -106,12 +107,21 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     bad_optional_access() = default;
     virtual ~bad_optional_access() = default;
 
+#if __cpp_lib_constexpr_exceptions >= 202502L
+    constexpr
+#endif
     const char* what() const noexcept override
     { return "bad optional access"; }
   };
 
   // XXX Does not belong here.
-  [[__noreturn__]] inline void
+  [[__noreturn__]]
+#if __cpp_lib_constexpr_exceptions >= 202502L
+  constexpr
+#else
+  inline
+#endif
+  void
   __throw_bad_optional_access()
   { _GLIBCXX_THROW_OR_ABORT(bad_optional_access()); }
 
--- libstdc++-v3/include/std/expected.jj        2025-05-13 14:07:49.694174124 
+0200
+++ libstdc++-v3/include/std/expected   2025-07-16 09:18:01.499703231 +0200
@@ -36,6 +36,7 @@
 #define __glibcxx_want_expected
 #define __glibcxx_want_freestanding_expected
 #define __glibcxx_want_constrained_equality
+#define __glibcxx_want_constexpr_exceptions
 #include <bits/version.h>
 
 #ifdef __cpp_lib_expected // C++ >= 23 && __cpp_concepts >= 202002L
@@ -77,21 +78,32 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Er>
     class bad_expected_access;
 
+#if __cpp_lib_constexpr_exceptions >= 202502L
+#define _GLIBCXX_CONSTEXPR_BAD_EXPECTED_ACCESS constexpr
+#else
+#define _GLIBCXX_CONSTEXPR_BAD_EXPECTED_ACCESS
+#endif
+
   template<>
     class bad_expected_access<void> : public exception
     {
     protected:
-      bad_expected_access() noexcept { }
+      _GLIBCXX_CONSTEXPR_BAD_EXPECTED_ACCESS bad_expected_access() noexcept { }
+      _GLIBCXX_CONSTEXPR_BAD_EXPECTED_ACCESS
       bad_expected_access(const bad_expected_access&) noexcept = default;
+      _GLIBCXX_CONSTEXPR_BAD_EXPECTED_ACCESS
       bad_expected_access(bad_expected_access&&) noexcept = default;
+      _GLIBCXX_CONSTEXPR_BAD_EXPECTED_ACCESS
       bad_expected_access& operator=(const bad_expected_access&) noexcept = 
default;
+      _GLIBCXX_CONSTEXPR_BAD_EXPECTED_ACCESS
       bad_expected_access& operator=(bad_expected_access&&) noexcept = default;
+      _GLIBCXX_CONSTEXPR_BAD_EXPECTED_ACCESS
       ~bad_expected_access() = default;
 
     public:
 
       [[nodiscard]]
-      const char*
+      _GLIBCXX_CONSTEXPR_BAD_EXPECTED_ACCESS const char*
       what() const noexcept override
       { return "bad access to std::expected without expected value"; }
     };
@@ -99,28 +111,28 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<typename _Er>
     class bad_expected_access : public bad_expected_access<void> {
     public:
-      explicit
+      _GLIBCXX_CONSTEXPR_BAD_EXPECTED_ACCESS explicit
       bad_expected_access(_Er __e) : _M_unex(std::move(__e)) { }
 
       // XXX const char* what() const noexcept override;
 
       [[nodiscard]]
-      _Er&
+      _GLIBCXX_CONSTEXPR_BAD_EXPECTED_ACCESS _Er&
       error() & noexcept
       { return _M_unex; }
 
       [[nodiscard]]
-      const _Er&
+      _GLIBCXX_CONSTEXPR_BAD_EXPECTED_ACCESS const _Er&
       error() const & noexcept
       { return _M_unex; }
 
       [[nodiscard]]
-      _Er&&
+      _GLIBCXX_CONSTEXPR_BAD_EXPECTED_ACCESS _Er&&
       error() && noexcept
       { return std::move(_M_unex); }
 
       [[nodiscard]]
-      const _Er&&
+      _GLIBCXX_CONSTEXPR_BAD_EXPECTED_ACCESS const _Er&&
       error() const && noexcept
       { return std::move(_M_unex); }
 
--- libstdc++-v3/include/std/format.jj  2025-07-14 12:51:45.839639020 +0200
+++ libstdc++-v3/include/std/format     2025-07-16 10:28:38.140973912 +0200
@@ -38,6 +38,7 @@
 #define __glibcxx_want_format
 #define __glibcxx_want_format_ranges
 #define __glibcxx_want_format_uchar
+#define __glibcxx_want_constexpr_exceptions
 #include <bits/version.h>
 
 #ifdef __cpp_lib_format // C++ >= 20 && HOSTED
@@ -214,12 +215,20 @@ namespace __format
       formatter& operator=(const formatter&) = delete;
     };
 
+#if __cpp_lib_constexpr_exceptions >= 202502L
+#define _GLIBCXX_CONSTEXPR_FORMAT_ERROR constexpr
+#else
+#define _GLIBCXX_CONSTEXPR_FORMAT_ERROR
+#endif
+
   // [format.error], class format_error
   class format_error : public runtime_error
   {
   public:
-    explicit format_error(const string& __what) : runtime_error(__what) { }
-    explicit format_error(const char* __what) : runtime_error(__what) { }
+    _GLIBCXX_CONSTEXPR_FORMAT_ERROR explicit format_error(const string& __what)
+    : runtime_error(__what) { }
+    _GLIBCXX_CONSTEXPR_FORMAT_ERROR explicit format_error(const char* __what)
+    : runtime_error(__what) { }
   };
 
   /// @cond undocumented
@@ -228,6 +237,8 @@ namespace __format
   __throw_format_error(const char* __what)
   { _GLIBCXX_THROW_OR_ABORT(format_error(__what)); }
 
+#undef _GLIBCXX_CONSTEXPR_FORMAT_ERROR
+
 namespace __format
 {
   // XXX use named functions for each constexpr error?
--- libstdc++-v3/include/std/variant.jj 2025-07-15 14:49:29.976515413 +0200
+++ libstdc++-v3/include/std/variant    2025-07-16 09:14:19.093744197 +0200
@@ -36,6 +36,7 @@
 #define __glibcxx_want_freestanding_variant
 #define __glibcxx_want_variant
 #define __glibcxx_want_constrained_equality
+#define __glibcxx_want_constexpr_exceptions
 #include <bits/version.h>
 
 #ifdef __cpp_lib_variant // C++ >= 17
@@ -1394,24 +1395,33 @@ namespace __detail::__variant
                   && (is_swappable_v<_Types> && ...))>
     swap(variant<_Types...>&, variant<_Types...>&) = delete;
 
-  [[noreturn]] void __throw_bad_variant_access(unsigned);
+#if __cpp_lib_constexpr_exceptions >= 202502L
+#define _GLIBCXX_CONSTEXPR_BAD_VARIANT_ACCESS constexpr
+#else
+#define _GLIBCXX_CONSTEXPR_BAD_VARIANT_ACCESS
+#endif
+  [[noreturn]] _GLIBCXX_CONSTEXPR_BAD_VARIANT_ACCESS void
+  __throw_bad_variant_access(unsigned);
 
   class bad_variant_access : public exception
   {
   public:
-    bad_variant_access() noexcept { }
+    _GLIBCXX_CONSTEXPR_BAD_VARIANT_ACCESS bad_variant_access() noexcept { }
 
-    const char* what() const noexcept override
+    _GLIBCXX_CONSTEXPR_BAD_VARIANT_ACCESS const char* what()
+    const noexcept override
     { return _M_reason; }
 
   private:
     // Must only be called with a string literal
+    _GLIBCXX_CONSTEXPR_BAD_VARIANT_ACCESS
     bad_variant_access(const char* __reason) noexcept : _M_reason(__reason) { }
 
     // Must point to a string with static storage duration:
     const char* _M_reason = "bad variant access";
 
-    friend void __throw_bad_variant_access([[maybe_unused]] unsigned __n)
+    friend _GLIBCXX_CONSTEXPR_BAD_VARIANT_ACCESS void
+    __throw_bad_variant_access([[maybe_unused]] unsigned __n)
     {
       [[maybe_unused]] static constexpr const char* __reasons[] = {
        "std::get: wrong index for variant",
@@ -1421,6 +1431,7 @@ namespace __detail::__variant
       };
       _GLIBCXX_THROW_OR_ABORT(bad_variant_access(__reasons[__n % 4u]));
     }
+#undef _GLIBCXX_CONSTEXPR_BAD_VARIANT_ACCESS
   };
 
   template<typename... _Types>
--- libstdc++-v3/testsuite/18_support/exception/version.cc.jj   2025-07-16 
09:35:00.719063821 +0200
+++ libstdc++-v3/testsuite/18_support/exception/version.cc      2025-07-16 
09:35:23.446760384 +0200
@@ -5,6 +5,6 @@
 
 #ifndef __cpp_lib_constexpr_exceptions
 # error "Feature test macro for constexpr_exceptions is missing in <exception>"
-#elif __cpp_lib_constexpr_exceptions < 202411L
+#elif __cpp_lib_constexpr_exceptions < 202502L
 # error "Feature test macro for constexpr_exceptions has wrong value in 
<exception>"
 #endif
--- libstdc++-v3/testsuite/19_diagnostics/runtime_error/constexpr.cc.jj 
2025-07-16 09:35:23.446760384 +0200
+++ libstdc++-v3/testsuite/19_diagnostics/runtime_error/constexpr.cc    
2025-07-16 09:35:23.446760384 +0200
@@ -0,0 +1,73 @@
+// { dg-do compile { target c++26 } }
+
+#include <string>
+#include <stdexcept>
+#include <testsuite_hooks.h>
+
+template <typename T>
+constexpr bool test01()
+{
+  try
+    {
+      std::string s = "This is the first runtime error";
+      throw T(s);
+    }
+  catch (const T &x)
+    {
+      VERIFY( std::string(x.what()) == "This is the first runtime error" );
+    }
+  try
+    {
+      throw T("This is the second runtime error");
+    }
+  catch (const std::runtime_error &x)
+    {
+      VERIFY( std::string(x.what()) == "This is the second runtime error" );
+    }
+  std::string s = "This is the third runtime error";
+  T l(s);
+  try
+    {
+      throw T(l);
+    }
+  catch (const std::runtime_error &x)
+    {
+      VERIFY( std::string(x.what()) == "This is the third runtime error" );
+    }
+  VERIFY( std::string(l.what()) == "This is the third runtime error" );
+  s = "This is the fourth runtime error";
+  l = T(s);
+  try
+    {
+      throw T(std::move(l));
+    }
+  catch (const T &x)
+    {
+      VERIFY( std::string(x.what()) == "This is the fourth runtime error" );
+    }
+  T l2(s);
+  l2 = T("This is the fifth runtime error");
+  VERIFY( std::string(l2.what()) == "This is the fifth runtime error" );
+  T l3("This is the sixth runtime error");
+  VERIFY( std::string(l3.what()) == "This is the sixth runtime error" );
+  l3 = l2;
+  VERIFY( std::string(l2.what()) == "This is the fifth runtime error" );
+  VERIFY( std::string(l3.what()) == "This is the fifth runtime error" );
+  l3 = T("This is the seventh runtime error");
+  l2 = std::move(l3);
+  VERIFY( std::string(l2.what()) == "This is the seventh runtime error" );
+  return true;
+}
+
+static_assert(test01<std::runtime_error>());
+static_assert(test01<std::range_error>());
+static_assert(test01<std::overflow_error>());
+static_assert(test01<std::underflow_error>());
+
+int main(void)
+{
+  test01<std::runtime_error>();
+  test01<std::range_error>();
+  test01<std::overflow_error>();
+  test01<std::underflow_error>();
+}
--- libstdc++-v3/testsuite/19_diagnostics/headers/stdexcept/version.cc.jj       
2025-07-16 09:35:23.447760370 +0200
+++ libstdc++-v3/testsuite/19_diagnostics/headers/stdexcept/version.cc  
2025-07-16 09:35:23.446760384 +0200
@@ -0,0 +1,10 @@
+// { dg-do preprocess { target c++26 } }
+// { dg-add-options no_pch }
+
+#include <stdexcept>
+
+#ifndef __cpp_lib_constexpr_exceptions
+# error "Feature test macro for constexpr_exceptions is missing in <stdexcept>"
+#elif __cpp_lib_constexpr_exceptions < 202502L
+# error "Feature test macro for constexpr_exceptions has wrong value in 
<stdexcept>"
+#endif
--- libstdc++-v3/testsuite/19_diagnostics/logic_error/constexpr.cc.jj   
2025-07-16 09:35:23.447760370 +0200
+++ libstdc++-v3/testsuite/19_diagnostics/logic_error/constexpr.cc      
2025-07-16 09:35:23.447760370 +0200
@@ -0,0 +1,75 @@
+// { dg-do compile { target c++26 } }
+
+#include <string>
+#include <stdexcept>
+#include <testsuite_hooks.h>
+
+template <typename T>
+constexpr bool test01()
+{
+  try
+    {
+      std::string s = "This is the first logic error";
+      throw T(s);
+    }
+  catch (const T &x)
+    {
+      VERIFY( std::string(x.what()) == "This is the first logic error" );
+    }
+  try
+    {
+      throw T("This is the second logic error");
+    }
+  catch (const std::logic_error &x)
+    {
+      VERIFY( std::string(x.what()) == "This is the second logic error" );
+    }
+  std::string s = "This is the third logic error";
+  T l(s);
+  try
+    {
+      throw T(l);
+    }
+  catch (const std::logic_error &x)
+    {
+      VERIFY( std::string(x.what()) == "This is the third logic error" );
+    }
+  VERIFY( std::string(l.what()) == "This is the third logic error" );
+  s = "This is the fourth logic error";
+  l = T(s);
+  try
+    {
+      throw T(std::move(l));
+    }
+  catch (const T &x)
+    {
+      VERIFY( std::string(x.what()) == "This is the fourth logic error" );
+    }
+  T l2(s);
+  l2 = T("This is the fifth logic error");
+  VERIFY( std::string(l2.what()) == "This is the fifth logic error" );
+  T l3("This is the sixth logic error");
+  VERIFY( std::string(l3.what()) == "This is the sixth logic error" );
+  l3 = l2;
+  VERIFY( std::string(l2.what()) == "This is the fifth logic error" );
+  VERIFY( std::string(l3.what()) == "This is the fifth logic error" );
+  l3 = T("This is the seventh logic error");
+  l2 = std::move(l3);
+  VERIFY( std::string(l2.what()) == "This is the seventh logic error" );
+  return true;
+}
+
+static_assert(test01<std::logic_error>());
+static_assert(test01<std::domain_error>());
+static_assert(test01<std::invalid_argument>());
+static_assert(test01<std::length_error>());
+static_assert(test01<std::out_of_range>());
+
+int main(void)
+{
+  test01<std::logic_error>();
+  test01<std::domain_error>();
+  test01<std::invalid_argument>();
+  test01<std::length_error>();
+  test01<std::out_of_range>();
+}
--- libstdc++-v3/testsuite/20_util/expected/observers.cc.jj     2023-09-18 
15:14:49.012357785 +0200
+++ libstdc++-v3/testsuite/20_util/expected/observers.cc        2025-07-16 
10:11:47.076489425 +0200
@@ -77,7 +77,10 @@ test_value()
   return true;
 }
 
-void
+#if __cpp_lib_constexpr_exceptions >= 202502L
+constexpr
+#endif
+bool
 test_value_throw()
 {
   std::expected<int, int> e1 = std::unexpected(9);
@@ -87,6 +90,8 @@ test_value_throw()
     VERIFY( false );
   } catch (const std::bad_expected_access<int>& e) {
     VERIFY( e.error() == 9 );
+    long c = e.what()[0];
+    VERIFY( c == e.what()[0] );
   }
   try {
     std::move(e1).value();
@@ -122,6 +127,7 @@ test_value_throw()
   } catch (const std::bad_expected_access<int>& e) {
     VERIFY( e.error() == 8 );
   }
+  return true;
 }
 
 constexpr bool
@@ -218,6 +224,9 @@ int main()
   test_has_value();
   static_assert( test_value() );
   test_value();
+#if __cpp_lib_constexpr_exceptions >= 202502L
+  static_assert( test_value_throw() );
+#endif
   test_value_throw();
   static_assert( test_error() );
   test_error();
--- libstdc++-v3/testsuite/20_util/expected/version.cc.jj       2023-11-21 
21:00:52.135288116 +0100
+++ libstdc++-v3/testsuite/20_util/expected/version.cc  2025-07-16 
09:41:30.707859026 +0200
@@ -15,8 +15,17 @@
 # error "Feature-test macro for freestanding expected has wrong value in 
<version>"
 #endif
 
+#if __cplusplus > 202302L
+# ifndef __cpp_lib_constexpr_exceptions
+#  error "Feature test macro for constexpr_exceptions is missing in <version>"
+# elif __cpp_lib_constexpr_exceptions < 202502L
+#  error "Feature test macro for constexpr_exceptions has wrong value in 
<version>"
+# endif
+#endif
+
 #undef __cpp_lib_expected
 #undef __cpp_lib_freestanding_expected
+#undef __cpp_lib_constexpr_exceptions
 #include <expected>
 
 #ifndef __cpp_lib_expected
@@ -30,3 +39,11 @@
 #elif __cpp_lib_freestanding_expected != 202311L
 # error "Feature-test macro for freestanding expected has wrong value in 
<expected>"
 #endif
+
+#if __cplusplus > 202302L
+# ifndef __cpp_lib_constexpr_exceptions
+#  error "Feature test macro for constexpr_exceptions is missing in <expected>"
+# elif __cpp_lib_constexpr_exceptions < 202502L
+#  error "Feature test macro for constexpr_exceptions has wrong value in 
<expected>"
+# endif
+#endif
--- libstdc++-v3/testsuite/20_util/variant/constexpr.cc.jj      2023-11-16 
23:00:45.693383990 +0100
+++ libstdc++-v3/testsuite/20_util/variant/constexpr.cc 2025-07-16 
10:33:06.768389242 +0200
@@ -11,6 +11,9 @@
 # error "Feature test macro for variant has wrong value for C++20 in <variant>"
 #endif
 
+#if __cpp_lib_constexpr_exceptions >= 202502L
+#include <string>
+#endif
 #include <testsuite_hooks.h>
 
 
@@ -51,6 +54,39 @@ test_assign()
 
 static_assert( test_assign() );
 
+#if __cpp_lib_constexpr_exceptions >= 202502L
+constexpr bool test_get()
+{
+  VERIFY(std::get<1>(std::variant<int, std::string>("a")) == "a");
+  VERIFY(std::get<std::string>(std::variant<int, std::string>("a")) == "a");
+  {
+    try
+      {
+       std::get<0>(std::variant<int, std::string>("a"));
+      }
+    catch (const std::bad_variant_access& x)
+      {
+       long c = x.what()[0];
+       VERIFY( c == x.what()[0] );
+      }
+  }
+  {
+    try
+      {
+       std::get<int>(std::variant<int, std::string>("a"));
+      }
+    catch (const std::bad_variant_access& x)
+      {
+       long c = x.what()[0];
+       VERIFY( c == x.what()[0] );
+      }
+  }
+  return true;
+}
+
+static_assert (test_get() );
+#endif
+
 constexpr bool
 test_emplace()
 {
--- libstdc++-v3/testsuite/20_util/variant/version.cc.jj        2023-11-21 
21:00:52.135288116 +0100
+++ libstdc++-v3/testsuite/20_util/variant/version.cc   2025-07-16 
09:40:45.334464561 +0200
@@ -19,8 +19,17 @@
 #endif
 #endif
 
+#if __cplusplus > 202302L
+#ifndef __cpp_lib_constexpr_exceptions
+# error "Feature test macro for constexpr_exceptions is missing in <version>"
+#elif __cpp_lib_constexpr_exceptions < 202502L
+# error "Feature test macro for constexpr_exceptions has wrong value in 
<version>"
+#endif
+#endif
+
 #undef __cpp_lib_variant
 #undef __cpp_lib_freestanding_variant
+#undef __cpp_lib_constexpr_exceptions
 #include <variant>
 
 #if __cplusplus >= 202302L
@@ -30,3 +39,11 @@
 # error "Feature test macro for freestanding std::variant has wrong value in 
<variant>"
 #endif
 #endif
+
+#if __cplusplus > 202302L
+#ifndef __cpp_lib_constexpr_exceptions
+# error "Feature test macro for constexpr_exceptions is missing in <variant>"
+#elif __cpp_lib_constexpr_exceptions < 202502L
+# error "Feature test macro for constexpr_exceptions has wrong value in 
<variant>"
+#endif
+#endif
--- libstdc++-v3/testsuite/20_util/optional/constexpr/observers/3.cc.jj 
2025-01-02 20:54:32.980118142 +0100
+++ libstdc++-v3/testsuite/20_util/optional/constexpr/observers/3.cc    
2025-07-16 10:13:29.414121098 +0200
@@ -18,12 +18,45 @@
 // <http://www.gnu.org/licenses/>.
 
 #include <optional>
+#include <testsuite_hooks.h>
 
 struct value_type
 {
   int i;
 };
 
+#if __cpp_lib_constexpr_exceptions >= 202502L
+void eat(int x)
+{
+}
+
+constexpr bool test01()
+{
+  enum outcome_type { nothrow, caught, bad_catch };
+
+  outcome_type outcome {};
+  std::optional<value_type> o = std::nullopt;
+
+  try
+  {
+    eat(o.value().i);
+  }
+  catch(std::bad_optional_access const& x)
+  {
+    outcome = caught;
+    long c = x.what()[0];
+    VERIFY( c == x.what()[0] );
+  }
+  catch(...)
+  { outcome = bad_catch; }
+
+  VERIFY( outcome == caught );
+  return true;
+}
+
+static_assert( test01() );
+#endif
+
 int main()
 {
   constexpr std::optional<value_type> o { value_type { 51 } };
--- libstdc++-v3/testsuite/20_util/optional/version.cc.jj       2025-06-12 
19:51:32.788008818 +0200
+++ libstdc++-v3/testsuite/20_util/optional/version.cc  2025-07-16 
09:39:12.498703526 +0200
@@ -27,11 +27,18 @@
 # elif __cpp_lib_optional_range_support != 202406L
 #  error "Feature test macro for optional range support has wrong value for 
C++26 in <version>"
 # endif
+
+# ifndef __cpp_lib_constexpr_exceptions
+#  error "Feature test macro for constexpr_exceptions is missing in <version>"
+# elif __cpp_lib_constexpr_exceptions < 202502L
+#  error "Feature test macro for constexpr_exceptions has wrong value in 
<version>"
+# endif
 #endif
 
 #undef __cpp_lib_optional
 #undef __cpp_lib_freestanding_optional
 #undef __cpp_lib_optional_range_support
+#undef __cpp_lib_constexpr_exceptions
 #include <optional>
 
 #if __cplusplus >= 202302L
@@ -49,4 +56,10 @@
 # if __cpp_lib_optional_range_support != 202406L
 #  error "Feature test macro for optional range support has wrong value for 
C++26 in <optional>"
 # endif
+
+# ifndef __cpp_lib_constexpr_exceptions
+#  error "Feature test macro for constexpr_exceptions is missing in <optional>"
+# elif __cpp_lib_constexpr_exceptions < 202502L
+#  error "Feature test macro for constexpr_exceptions has wrong value in 
<optional>"
+# endif
 #endif

        Jakub

Reply via email to