{"id":2226693,"url":"http://patchwork.ozlabs.org/api/patches/2226693/?format=json","web_url":"http://patchwork.ozlabs.org/project/gcc/patch/bmm.hhuohcp8h4.gcc.gcc-TEST.peppe.55.1.1@forge-stage.sourceware.org/","project":{"id":17,"url":"http://patchwork.ozlabs.org/api/projects/17/?format=json","name":"GNU Compiler Collection","link_name":"gcc","list_id":"gcc-patches.gcc.gnu.org","list_email":"gcc-patches@gcc.gnu.org","web_url":null,"scm_url":null,"webscm_url":null,"list_archive_url":"","list_archive_url_format":"","commit_url_format":""},"msgid":"<bmm.hhuohcp8h4.gcc.gcc-TEST.peppe.55.1.1@forge-stage.sourceware.org>","list_archive_url":null,"date":"2026-04-22T18:25:46","name":"[v1,1/1] libstdc++: WIP: optional<T&> (P2988R12)","commit_ref":null,"pull_url":null,"state":"new","archived":false,"hash":"124e608c3a1dc62b9bbe1f0fec598fe020c0ac8a","submitter":{"id":93222,"url":"http://patchwork.ozlabs.org/api/people/93222/?format=json","name":"peppe via Sourceware Forge","email":"forge-bot+peppe@forge-stage.sourceware.org"},"delegate":null,"mbox":"http://patchwork.ozlabs.org/project/gcc/patch/bmm.hhuohcp8h4.gcc.gcc-TEST.peppe.55.1.1@forge-stage.sourceware.org/mbox/","series":[{"id":501075,"url":"http://patchwork.ozlabs.org/api/series/501075/?format=json","web_url":"http://patchwork.ozlabs.org/project/gcc/list/?series=501075","date":"2026-04-22T18:25:46","name":"WIP: libstdc++: WIP: optional<T&> (P2988R12)","version":1,"mbox":"http://patchwork.ozlabs.org/series/501075/mbox/"}],"comments":"http://patchwork.ozlabs.org/api/patches/2226693/comments/","check":"pending","checks":"http://patchwork.ozlabs.org/api/patches/2226693/checks/","tags":{},"related":[],"headers":{"Return-Path":"<gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org>","X-Original-To":["incoming@patchwork.ozlabs.org","gcc-patches@gcc.gnu.org"],"Delivered-To":["patchwork-incoming@legolas.ozlabs.org","gcc-patches@gcc.gnu.org"],"Authentication-Results":["legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org\n (client-ip=2620:52:6:3111::32; helo=vm01.sourceware.org;\n envelope-from=gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org;\n receiver=patchwork.ozlabs.org)","sourceware.org; dmarc=none (p=none dis=none)\n header.from=forge-stage.sourceware.org","sourceware.org;\n spf=pass smtp.mailfrom=forge-stage.sourceware.org","server2.sourceware.org;\n arc=none smtp.remote-ip=38.145.34.39"],"Received":["from vm01.sourceware.org (vm01.sourceware.org\n [IPv6:2620:52:6:3111::32])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519 server-signature ECDSA (secp384r1) server-digest SHA384)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4g17C80lFDz1yD5\n\tfor <incoming@patchwork.ozlabs.org>; Thu, 23 Apr 2026 04:33:24 +1000 (AEST)","from vm01.sourceware.org (localhost [127.0.0.1])\n\tby sourceware.org (Postfix) with ESMTP id 1A5534423330\n\tfor <incoming@patchwork.ozlabs.org>; Wed, 22 Apr 2026 18:33:22 +0000 (GMT)","from forge-stage.sourceware.org (vm08.sourceware.org [38.145.34.39])\n by sourceware.org (Postfix) with ESMTPS id D910E48FEF68\n for <gcc-patches@gcc.gnu.org>; Wed, 22 Apr 2026 18:26:40 +0000 (GMT)","from forge-stage.sourceware.org (localhost [IPv6:::1])\n (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n key-exchange x25519 server-signature ECDSA (prime256v1) server-digest SHA256)\n (No client certificate requested)\n by forge-stage.sourceware.org (Postfix) with ESMTPS id B490443473\n for <gcc-patches@gcc.gnu.org>; Wed, 22 Apr 2026 18:26:40 +0000 (UTC)"],"DKIM-Filter":["OpenDKIM Filter v2.11.0 sourceware.org 1A5534423330","OpenDKIM Filter v2.11.0 sourceware.org D910E48FEF68"],"DMARC-Filter":"OpenDMARC Filter v1.4.2 sourceware.org D910E48FEF68","ARC-Filter":"OpenARC Filter v1.0.0 sourceware.org D910E48FEF68","ARC-Seal":"i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1776882400; cv=none;\n b=xmmq9y6RLOxBDUfI2pjnmBa5GTOaeH/SlKh+xM1h0+kxoYC9gMMG0wrZ1z44C0Rdr8L3baZGauqPW4lJ5aJfZnpk+ywLVGC6QIUfsuggnXJsu0pj9udYH6/XfeoijLsO19NZHv+3IlhF2Cbj7T+SdExvIG+UE3oRq2ruqzQtAG0=","ARC-Message-Signature":"i=1; a=rsa-sha256; d=sourceware.org; s=key;\n t=1776882400; c=relaxed/simple;\n bh=Ca/ByBO8OlIjbDCBAwEmZUeTZcgLa1dA4G94jNX6qmE=;\n h=From:Date:Subject:To:Message-ID;\n b=f1j31UU2Da2IEK7BlGve53Bz0RMcTd4iecLWSKyu+SxAhRvGFFhDcJBhkeGA02fa169h7mhZqP1o3qh5tGV9DqByXUG6DJsvoIazQ3M0ZTjRnFbbg0us11uWEio1n+VNQvvp8rW7cleE0R5s0Uil1AKLwKqO0i44vOWa6VCm8i0=","ARC-Authentication-Results":"i=1; server2.sourceware.org","From":"peppe via Sourceware Forge <forge-bot+peppe@forge-stage.sourceware.org>","Date":"Wed, 22 Apr 2026 18:25:46 +0000","Subject":"[PATCH v1 1/1] libstdc++: WIP: optional<T&> (P2988R12)","To":"gcc-patches mailing list <gcc-patches@gcc.gnu.org>","Message-ID":"\n <bmm.hhuohcp8h4.gcc.gcc-TEST.peppe.55.1.1@forge-stage.sourceware.org>","X-Mailer":"batrachomyomachia","X-Pull-Request-Organization":"gcc","X-Pull-Request-Repository":"gcc-TEST","X-Pull-Request":"https://forge.sourceware.org/gcc/gcc-TEST/pulls/55","References":"\n <bmm.hhuohcp8h4.gcc.gcc-TEST.peppe.55.1.0@forge-stage.sourceware.org>","In-Reply-To":"\n <bmm.hhuohcp8h4.gcc.gcc-TEST.peppe.55.1.0@forge-stage.sourceware.org>","X-Patch-URL":"\n https://forge.sourceware.org/peppe/gcc-TEST/commit/a328791d948e3772b8a40645c9ffef1df1cf185a","X-BeenThere":"gcc-patches@gcc.gnu.org","X-Mailman-Version":"2.1.30","Precedence":"list","List-Id":"Gcc-patches mailing list <gcc-patches.gcc.gnu.org>","List-Unsubscribe":"<https://gcc.gnu.org/mailman/options/gcc-patches>,\n <mailto:gcc-patches-request@gcc.gnu.org?subject=unsubscribe>","List-Archive":"<https://gcc.gnu.org/pipermail/gcc-patches/>","List-Post":"<mailto:gcc-patches@gcc.gnu.org>","List-Help":"<mailto:gcc-patches-request@gcc.gnu.org?subject=help>","List-Subscribe":"<https://gcc.gnu.org/mailman/listinfo/gcc-patches>,\n <mailto:gcc-patches-request@gcc.gnu.org?subject=subscribe>","Reply-To":"gcc-patches mailing list <gcc-patches@gcc.gnu.org>,\n peppe@noreply.localhost","Errors-To":"gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org"},"content":"From: Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>\n\nINCOMPLETE (needs lots of tests!). The value of the FTM is made-up.\n\nThe converting constructors from optional<U> are tedious to type.\nMaybe deduce the argument and centralize the implementation?\n\nNoted a few things to address in P2988R12, editorially / easy LWG issues.\n\nmake_optional: the proposed change breaks\n  make_optional<T>({braced-init-list}), wanted? Disabled for now.\n\nlibstdc++-v3/ChangeLog:\n\n\t* include/bits/version.def (__cpp_lib_optional): Bump the\n\tfeature-testing macro.\n\t* include/bits/version.h: Regenerate.\n\t* include/std/optional (optional): Add specialization for\n\treferences. Do minor amendments to the primary template as\n\tper P2988R12.\n\t* testsuite/20_util/optional/requirements.cc: Amend the\n\tfeature-testing macro test.\n\t* testsuite/20_util/optional/requirements_neg.cc: Amend the\n\ttesting of optional<T&>.\n\t* testsuite/20_util/optional/version.cc: Amend the\n\tfeature-testing macro test.\n---\n libstdc++-v3/include/bits/version.def         |   4 +\n libstdc++-v3/include/bits/version.h           |   7 +-\n libstdc++-v3/include/std/optional             | 347 +++++++++++++++++-\n .../20_util/optional/requirements.cc          |   4 +-\n .../20_util/optional/requirements_neg.cc      |  17 +-\n .../testsuite/20_util/optional/version.cc     |   4 +-\n 6 files changed, 374 insertions(+), 9 deletions(-)","diff":"diff --git a/libstdc++-v3/include/bits/version.def b/libstdc++-v3/include/bits/version.def\nindex 9ab22cc519f9..ffb8fe886d41 100644\n--- a/libstdc++-v3/include/bits/version.def\n+++ b/libstdc++-v3/include/bits/version.def\n@@ -836,6 +836,10 @@ ftms = {\n // Moved down here (after concepts) by topological sort.\n ftms = {\n   name = optional;\n+  values = {\n+    v = 202506;\n+    cxxmin = 26;\n+  };\n   values = {\n     v = 202110;\n     cxxmin = 23;\ndiff --git a/libstdc++-v3/include/bits/version.h b/libstdc++-v3/include/bits/version.h\nindex 371a7ba3b1a0..c07ea48b4b5c 100644\n--- a/libstdc++-v3/include/bits/version.h\n+++ b/libstdc++-v3/include/bits/version.h\n@@ -936,7 +936,12 @@\n #undef __glibcxx_want_concepts\n \n #if !defined(__cpp_lib_optional)\n-# if (__cplusplus >= 202100L) && (__glibcxx_concepts)\n+# if (__cplusplus >  202302L)\n+#  define __glibcxx_optional 202506L\n+#  if defined(__glibcxx_want_all) || defined(__glibcxx_want_optional)\n+#   define __cpp_lib_optional 202506L\n+#  endif\n+# elif (__cplusplus >= 202100L) && (__glibcxx_concepts)\n #  define __glibcxx_optional 202110L\n #  if defined(__glibcxx_want_all) || defined(__glibcxx_want_optional)\n #   define __cpp_lib_optional 202110L\ndiff --git a/libstdc++-v3/include/std/optional b/libstdc++-v3/include/std/optional\nindex a616dc07b107..c92d774b50d2 100644\n--- a/libstdc++-v3/include/std/optional\n+++ b/libstdc++-v3/include/std/optional\n@@ -771,6 +771,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION\n # define _GLIBCXX_USE_CONSTRAINTS_FOR_OPTIONAL 1\n #endif\n \n+  template<typename _Tp>\n+    inline constexpr bool __is_valid_contained_type_for_optional =\n+      (\n+#if __cpp_lib_optional >= 202506L\n+\tis_lvalue_reference_v<_Tp> ||\n+#endif\n+\t(is_object_v<_Tp> && !is_array_v<_Tp>)\n+      )\n+      && !is_same_v<remove_cv_t<remove_reference_t<_Tp>>, nullopt_t>\n+      && !is_same_v<remove_cv_t<remove_reference_t<_Tp>>, in_place_t>\n+      && (!is_object_v<_Tp> || is_destructible_v<_Tp>);\n+\n   /**\n     * @brief Class template for optional values.\n     */\n@@ -789,9 +801,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION\n \t// Unique tag type.\n \toptional<_Tp>>\n     {\n-      static_assert(!is_same_v<remove_cv_t<_Tp>, nullopt_t>);\n-      static_assert(!is_same_v<remove_cv_t<_Tp>, in_place_t>);\n-      static_assert(is_object_v<_Tp> && !is_array_v<_Tp>);\n+      static_assert(__is_valid_contained_type_for_optional<_Tp>);\n \n     private:\n       using _Base = _Optional_base<_Tp>;\n@@ -1329,6 +1339,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION\n \ttransform(_Fn&& __f) &\n \t{\n \t  using _Up = remove_cv_t<invoke_result_t<_Fn, _Tp&>>;\n+\t  static_assert(__is_valid_contained_type_for_optional<_Up>,\n+\t\t\t\"the function passed to std::optional<T>::transform \"\n+\t\t\t\"must return a type \"\n+\t\t\t\"that can be stored inside std::optional\");\n \t  if (has_value())\n \t    return optional<_Up>(_Optional_func<_Fn>{__f}, _M_get());\n \t  else\n@@ -1340,6 +1354,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION\n \ttransform(_Fn&& __f) const &\n \t{\n \t  using _Up = remove_cv_t<invoke_result_t<_Fn, const _Tp&>>;\n+\t  static_assert(__is_valid_contained_type_for_optional<_Up>,\n+\t\t\t\"the function passed to std::optional<T>::transform \"\n+\t\t\t\"must return a type \"\n+\t\t\t\"that can be stored inside std::optional\");\n \t  if (has_value())\n \t    return optional<_Up>(_Optional_func<_Fn>{__f}, _M_get());\n \t  else\n@@ -1351,6 +1369,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION\n \ttransform(_Fn&& __f) &&\n \t{\n \t  using _Up = remove_cv_t<invoke_result_t<_Fn, _Tp>>;\n+\t  static_assert(__is_valid_contained_type_for_optional<_Up>,\n+\t\t\t\"the function passed to std::optional<T>::transform \"\n+\t\t\t\"must return a type \"\n+\t\t\t\"that can be stored inside std::optional\");\n \t  if (has_value())\n \t    return optional<_Up>(_Optional_func<_Fn>{__f}, std::move(_M_get()));\n \t  else\n@@ -1362,6 +1384,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION\n \ttransform(_Fn&& __f) const &&\n \t{\n \t  using _Up = remove_cv_t<invoke_result_t<_Fn, const _Tp>>;\n+\t  static_assert(__is_valid_contained_type_for_optional<_Up>,\n+\t\t\t\"the function passed to std::optional<T>::transform \"\n+\t\t\t\"must return a type \"\n+\t\t\t\"that can be stored inside std::optional\");\n \t  if (has_value())\n \t    return optional<_Up>(_Optional_func<_Fn>{__f}, std::move(_M_get()));\n \t  else\n@@ -1416,6 +1442,306 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION\n #endif\n     };\n \n+#if __cpp_lib_optional >= 202506L // C++26\n+  template<typename _Tp>\n+    class optional<_Tp&>\n+    {\n+      static_assert(__is_valid_contained_type_for_optional<_Tp&>);\n+\n+    public:\n+      using value_type = _Tp;\n+      using iterator = __gnu_cxx::__normal_iterator<_Tp*, optional>;\n+\n+      // Constructors.\n+      constexpr optional() noexcept = default;\n+      constexpr optional(nullopt_t) noexcept : optional() {}\n+      constexpr optional(const optional&) noexcept = default;\n+\n+      template<typename _Arg>\n+\trequires is_constructible_v<_Tp&, _Arg>\n+\t  && (!reference_constructs_from_temporary_v<_Tp&, _Arg>)\n+\texplicit constexpr\n+\toptional(in_place_t, _Arg&& __arg)\n+\t{\n+\t  __convert_ref_init_val(std::forward<_Arg>(__arg));\n+\t}\n+\n+      template<typename _Up>\n+\trequires (!is_same_v<remove_cvref_t<_Up>, optional>)\n+\t  && (!is_same_v<remove_cvref_t<_Up>, in_place_t>)\n+\t  && is_constructible_v<_Tp&, _Up>\n+\t  && (!reference_constructs_from_temporary_v<_Tp&, _Up>)\n+\texplicit(!is_convertible_v<_Up, _Tp&>)\n+\tconstexpr\n+\toptional(_Up&& __u)\n+\tnoexcept(is_nothrow_constructible_v<_Tp&, _Up>)\n+\t{\n+\t  __convert_ref_init_val(std::forward<_Up>(__u));\n+\t}\n+\n+      template<typename _Up>\n+\trequires (!is_same_v<remove_cvref_t<_Up>, optional>)\n+\t  && (!is_same_v<remove_cvref_t<_Up>, in_place_t>)\n+\t  && is_constructible_v<_Tp&, _Up>\n+\t  && reference_constructs_from_temporary_v<_Tp&, _Up>\n+\texplicit(!is_convertible_v<_Up, _Tp&>)\n+\tconstexpr\n+\toptional(_Up&& __u) = delete;\n+\n+      // optional<U> &\n+      template<typename _Up>\n+\trequires (!is_same_v<remove_cv_t<_Tp>, optional<_Up>>)\n+\t  && (!is_same_v<_Tp&, _Up>)\n+\t  && is_constructible_v<_Tp&, _Up&>\n+\t  && (!reference_constructs_from_temporary_v<_Tp&, _Up&>)\n+\texplicit(!is_convertible_v<_Up&, _Tp&>)\n+\tconstexpr\n+\toptional(optional<_Up>& __rhs)\n+\tnoexcept(is_nothrow_constructible_v<_Tp&, _Up&>)\n+\t{\n+\t  if (__rhs)\n+\t    __convert_ref_init_val(*__rhs);\n+\t}\n+\n+      template<typename _Up>\n+\trequires (!is_same_v<remove_cv_t<_Tp>, optional<_Up>>)\n+\t  && (!is_same_v<_Tp&, _Up>)\n+\t  && is_constructible_v<_Tp&, _Up&>\n+\t  && reference_constructs_from_temporary_v<_Tp&, _Up&>\n+\texplicit(!is_convertible_v<_Up&, _Tp&>)\n+\tconstexpr\n+\toptional(optional<_Up>& __rhs) = delete;\n+\n+      // const optional<U>&\n+      template<typename _Up>\n+\trequires (!is_same_v<remove_cv_t<_Tp>, optional<_Up>>)\n+\t  && (!is_same_v<_Tp&, _Up>)\n+\t  && is_constructible_v<_Tp&, const _Up&>\n+\t  && (!reference_constructs_from_temporary_v<_Tp&, const _Up&>)\n+\texplicit(!is_convertible_v<const _Up&, _Tp&>)\n+\tconstexpr\n+\toptional(const optional<_Up>& __rhs)\n+\tnoexcept(is_nothrow_constructible_v<_Tp&, _Up&>)\n+\t{\n+\t  if (__rhs)\n+\t    __convert_ref_init_val(*__rhs);\n+\t}\n+\n+      template<typename _Up>\n+\trequires (!is_same_v<remove_cv_t<_Tp>, optional<_Up>>)\n+\t  && (!is_same_v<_Tp&, _Up>)\n+\t  && is_constructible_v<_Tp&, const _Up&>\n+\t  && reference_constructs_from_temporary_v<_Tp&, const _Up&>\n+\texplicit(!is_convertible_v<const _Up&, _Tp&>)\n+\tconstexpr\n+\toptional(const optional<_Up>& __rhs) = delete;\n+\n+      // optional<U>&&\n+      template<typename _Up>\n+\trequires (!is_same_v<remove_cv_t<_Tp>, optional<_Up>>)\n+\t  && (!is_same_v<_Tp&, _Up>)\n+\t  && is_constructible_v<_Tp&, _Up>\n+\t  && (!reference_constructs_from_temporary_v<_Tp&, _Up>)\n+\texplicit(!is_convertible_v<_Up, _Tp&>)\n+\tconstexpr\n+\toptional(optional<_Up>&& __rhs)\n+\tnoexcept(is_nothrow_constructible_v<_Tp&, _Up>)\n+\t{\n+\t  if (__rhs)\n+\t    __convert_ref_init_val(*std::move(__rhs));\n+\t}\n+\n+      template<typename _Up>\n+\trequires (!is_same_v<remove_cv_t<_Tp>, optional<_Up>>)\n+\t  && (!is_same_v<_Tp&, _Up>)\n+\t  && is_constructible_v<_Tp&, _Up>\n+\t  && reference_constructs_from_temporary_v<_Tp&, _Up>\n+\texplicit(!is_convertible_v<_Up, _Tp&>)\n+\tconstexpr\n+\toptional(optional<_Up>&& __rhs) = delete;\n+\n+      // const optional<U>&&\n+      template<typename _Up>\n+\trequires (!is_same_v<remove_cv_t<_Tp>, optional<_Up>>)\n+\t  && (!is_same_v<_Tp&, _Up>)\n+\t  && is_constructible_v<_Tp&, const _Up>\n+\t  && (!reference_constructs_from_temporary_v<_Tp&, _Up>)\n+\texplicit(!is_convertible_v<const _Up, _Tp&>)\n+\tconstexpr\n+\toptional(const optional<_Up>&& __rhs)\n+\tnoexcept(is_nothrow_constructible_v<_Tp&, const _Up>)\n+\t{\n+\t  if (__rhs)\n+\t    __convert_ref_init_val(*std::move(__rhs));\n+\t}\n+\n+      template<typename _Up>\n+\trequires (!is_same_v<remove_cv_t<_Tp>, optional<_Up>>)\n+\t  && (!is_same_v<_Tp&, _Up>)\n+\t  && is_constructible_v<_Tp&, const _Up>\n+\t  && reference_constructs_from_temporary_v<_Tp&, const _Up>\n+\texplicit(!is_convertible_v<const _Up, _Tp&>)\n+\tconstexpr\n+\toptional(const optional<_Up>&& __rhs) = delete;\n+\n+      constexpr ~optional() = default;\n+\n+      // Assignment.\n+      constexpr optional& operator=(nullopt_t) noexcept\n+      {\n+\t_M_val = nullptr;\n+\treturn *this;\n+      }\n+\n+      constexpr optional& operator=(const optional&) noexcept = default;\n+\n+      template<typename _Up>\n+\trequires is_constructible_v<_Tp&, _Up>\n+\t  && (!reference_constructs_from_temporary_v<_Tp&, _Up>)\n+\tconstexpr\n+\t_Tp&\n+\templace(_Up&& __u)\n+\tnoexcept(is_nothrow_constructible_v<_Tp&, _Up>)\n+\t{\n+\t  __convert_ref_init_val(std::forward<_Up>(__u));\n+\t  return *_M_val; // FIXME: this isn't specified in the paper as Returns:, but likely a typo? What else could it be?\n+\t}\n+\n+      // Swap.\n+      constexpr void swap(optional& __rhs) noexcept\n+      {\n+\tswap(_M_val, __rhs._M_val);\n+      }\n+\n+      // Iterator support.\n+      constexpr iterator begin() const noexcept\n+      {\n+\treturn iterator(_M_val);\n+      }\n+\n+      constexpr iterator end() const noexcept\n+      {\n+\treturn begin() + has_value();\n+      }\n+\n+      // Observers.\n+      constexpr _Tp* operator->() const noexcept\n+      {\n+\t__glibcxx_assert(_M_val); // hardened precondition\n+        return _M_val;\n+      }\n+\n+      constexpr _Tp& operator*() const noexcept\n+      {\n+\t__glibcxx_assert(_M_val); // hardened precondition\n+        return *_M_val;\n+      }\n+\n+      constexpr explicit operator bool() const noexcept\n+      {\n+        return _M_val;\n+      }\n+\n+      constexpr bool has_value() const noexcept\n+      {\n+        return _M_val;\n+      }\n+\n+      constexpr _Tp& value() const\n+      {\n+        if (_M_val)\n+          return *_M_val;\n+        __throw_bad_optional_access();\n+      }\n+\n+      template<typename _Up = remove_cv_t<_Tp>>\n+\tconstexpr remove_cv_t<_Tp>\n+\tvalue_or(_Up&& __u) const\n+\t{\n+          using _Xp = remove_cv_t<_Tp>;\n+\t  static_assert(is_constructible_v<_Xp, _Tp&>);\n+\t  static_assert(is_convertible_v<_Up, _Xp>);\n+\t  return _M_val ? *_M_val : static_cast<_Xp>(std::forward<_Up>(__u));\n+\t}\n+\n+      // Monadic operations.\n+      template<typename _Fn>\n+\tconstexpr auto\n+\tand_then(_Fn&& __f) const\n+\t{\n+\t  using _Up = invoke_result_t<_Fn, _Tp&>;\n+\t  static_assert(__is_optional_v<remove_cvref_t<_Up>>,\n+\t\t\t\"the function passed to std::optional<T&>::and_then \"\n+\t\t\t\"must return a std::optional\");\n+\t  if (has_value())\n+\t    return std::__invoke(std::forward<_Fn>(__f), *_M_val);\n+\t  else\n+\t    return remove_cvref_t<_Up>();\n+\t}\n+\n+      template<typename _Fn>\n+\tconstexpr\n+\toptional<remove_cv_t<invoke_result_t<_Fn, _Tp&>>> // TODO why is it spelled out in the paper instead of `auto`? Like the wording for the primary template\n+\ttransform(_Fn&& __f) const\n+\t{\n+\t  using _Up = remove_cv_t<invoke_result_t<_Fn, _Tp&>>;\n+\t  // FIXME not 100% sure yet how to express the Mandates here \"(The declaration U u(invoke(std::forward<F>(f), *val)); is well-formed for some invented variable u.)\".\n+\t  // TODO: It seems that this Mandates also missing from our implementation of the primary template...?\n+\n+\t  // FIXME why isn't there in the paper a Mandates that U is a valid contained type for optional? Like in the wording for the primary template.\n+\t  if (has_value())\n+\t    return optional<_Up>(_Optional_func<_Fn>{__f}, *_M_val); // TODO the sample impl in the paper seems wrong, as that requires U to be movable (?). This is our primary's template impl which builds in place, and that seems like a better idea\n+\t  else\n+\t    return optional<_Up>();\n+\t}\n+\n+      template<typename _Fn>\n+\trequires invocable<_Fn>\n+\tconstexpr\n+\toptional\n+\tor_else(_Fn&& __f) const\n+\t{\n+\t  static_assert(is_same_v<remove_cvref_t<invoke_result_t<_Fn>>, optional>,\n+\t\t\t\"the function passed to std::optional<T&>::or_else \"\n+\t\t\t\"must return a std::optional<T&>\");\n+\t  if (has_value())\n+\t    return *_M_val; // FIXME in the paper it's spelled like this. I'm not sure yet why it's not spelled `return *this`, like in the primary template's wording? Does this have implications on e.g. lifetime? Suppose one has an object T in some storage, creates an optional<T&> bound to that object, destroys the object, calls opt.or_else(). Is that UB because of the dereference or should it just copy the reference without accessing the (destroyed) object? Should it be UB? The object could be subsequently transparently replaced and the result of or_else bound to the new object...\n+\t  else\n+\t    return std::forward<_Fn>(__f)();\n+\t}\n+\n+      // Modifiers.\n+      constexpr void reset() noexcept\n+      {\n+\t_M_val = nullptr;\n+      }\n+\n+    private:\n+      _Tp *_M_val = nullptr;\n+\n+      template<typename _Up>\n+\tconstexpr\n+\tvoid\n+\t__convert_ref_init_val(_Up&& __u)\n+\tnoexcept\n+\t{\n+\t  _Tp& __r(std::forward<_Up>(__u));\n+\t  _M_val = std::addressof(__r);\n+\t}\n+\n+      template<typename _Up> friend class optional;\n+\n+      template<typename _Fn, typename _Value>\n+\texplicit constexpr\n+\toptional(_Optional_func<_Fn> __f, _Value&& __v)\n+\t{\n+          // TODO: double check this\n+\t  _Tp& __r = std::__invoke(std::forward<_Fn>(__f._M_f), std::forward<_Value>(__v));\n+\t  _M_val = std::addressof(__r);\n+\t}\n+    };\n+#endif // __cpp_lib_optional >= 202506L\n+\n   template<typename _Tp>\n     using __optional_relop_t =\n       enable_if_t<is_convertible_v<_Tp, bool>, bool>;\n@@ -1694,20 +2020,31 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION\n \n   // Swap and creation functions.\n \n+  template<typename _Tp>\n+    inline constexpr bool __is_optional_swappable =\n+#if __cpp_lib_optional >= 202506L\n+      is_reference_v<_Tp> ||\n+#endif\n+      (is_move_constructible_v<_Tp> && is_swappable_v<_Tp>);\n+\n   // _GLIBCXX_RESOLVE_LIB_DEFECTS\n   // 2748. swappable traits for optionals\n   template<typename _Tp>\n     _GLIBCXX20_CONSTEXPR\n-    inline enable_if_t<is_move_constructible_v<_Tp> && is_swappable_v<_Tp>>\n+    inline enable_if_t<__is_optional_swappable<_Tp>>\n     swap(optional<_Tp>& __lhs, optional<_Tp>& __rhs)\n     noexcept(noexcept(__lhs.swap(__rhs)))\n     { __lhs.swap(__rhs); }\n \n   template<typename _Tp>\n-    enable_if_t<!(is_move_constructible_v<_Tp> && is_swappable_v<_Tp>)>\n+    enable_if_t<!__is_optional_swappable<_Tp>>\n     swap(optional<_Tp>&, optional<_Tp>&) = delete;\n \n+#if __cpp_lib_optional >= 202506L && 0 // FIXME. This change breaks make_optional<T>({braced init list}). Wanted?\n+  template<TODO> // \"Constraints: The call to make_optional does not use an explicit template-argument-list that begins with a type template-argument\"\n+#else\n   template<typename _Tp>\n+#endif\n     constexpr\n     enable_if_t<is_constructible_v<decay_t<_Tp>, _Tp>,\n \t\toptional<decay_t<_Tp>>>\ndiff --git a/libstdc++-v3/testsuite/20_util/optional/requirements.cc b/libstdc++-v3/testsuite/20_util/optional/requirements.cc\nindex 68e59057b5e3..3dc787bc89f5 100644\n--- a/libstdc++-v3/testsuite/20_util/optional/requirements.cc\n+++ b/libstdc++-v3/testsuite/20_util/optional/requirements.cc\n@@ -26,8 +26,10 @@\n # error \"Feature test macro for optional has wrong value in <optional>\"\n #elif __cplusplus == 202002L && __cpp_lib_optional != 202106L\n # error \"Feature test macro for optional has wrong value for C++20 in <optional>\"\n-#elif __cplusplus > 202002L && __cpp_lib_optional != 202110L\n+#elif __cplusplus == 202302L && __cpp_lib_optional != 202110L\n # error \"Feature test macro for optional has wrong value for C++23 in <version>\"\n+#elif __cplusplus > 202302L && __cpp_lib_optional != 202506L\n+# error \"Feature test macro for optional has wrong value for C++26 in <version>\"\n #endif\n \n #include <testsuite_hooks.h>\ndiff --git a/libstdc++-v3/testsuite/20_util/optional/requirements_neg.cc b/libstdc++-v3/testsuite/20_util/optional/requirements_neg.cc\nindex 688c305803e2..142fbbfc5151 100644\n--- a/libstdc++-v3/testsuite/20_util/optional/requirements_neg.cc\n+++ b/libstdc++-v3/testsuite/20_util/optional/requirements_neg.cc\n@@ -2,17 +2,32 @@\n \n #include <optional>\n \n+// C++ < 26:\n // T shall be a type other than cv in_place_t or cv nullopt_t\n // that meets the Cpp17Destructible requirements\n+// C++ >= 26:\n+// A type X is a valid contained type for optional if X is an lvalue reference\n+// type or a complete non-array object type, and remove_cvref_t<X> is a type\n+// other than in_place_t or nullopt_t. If a specialization of optional\n+// is instantiated with a type T that is not a valid contained type for\n+// optional, the program is ill-formed. If T is an object type,\n+// T shall meet the Cpp17Destructible requirements\n \n std::optional<std::nullopt_t> o1;        // { dg-error \"here\" }\n std::optional<const std::nullopt_t> o2;  // { dg-error \"here\" }\n std::optional<std::in_place_t> o3;       // { dg-error \"here\" }\n std::optional<const std::in_place_t> o4; // { dg-error \"here\" }\n-std::optional<int&> o5;                  // { dg-error \"here\" }\n+std::optional<int&> o5;                  // { dg-error \"here\" \"optional<T&> is a C++26 feature\" { target c++23_down } }\n std::optional<int[1]> o6;                // { dg-error \"here\" }\n std::optional<int[]> o7;                 // { dg-error \"here\" }\n std::optional<int()> o8;                 // { dg-error \"here\" }\n+std::optional<const int &> o9;           // { dg-error \"here\" \"optional<T&> is a C++26 feature\" { target c++23_down } }\n+std::optional<std::in_place_t &> o10;    // { dg-error \"here\" }\n+std::optional<const std::in_place_t &> o11; // { dg-error \"here\" }\n+std::optional<std::nullopt_t &> o12;     // { dg-error \"here\" }\n+std::optional<const std::nullopt_t &> o13; // { dg-error \"here\" }\n+std::optional<int &&> o14;               // { dg-error \"here\" }\n+std::optional<const int &&> o15;         // { dg-error \"here\" }\n \n // { dg-error \"static assertion failed\" \"\" { target *-*-* } 0 }\n \ndiff --git a/libstdc++-v3/testsuite/20_util/optional/version.cc b/libstdc++-v3/testsuite/20_util/optional/version.cc\nindex 657a3992422a..d029b31c072d 100644\n--- a/libstdc++-v3/testsuite/20_util/optional/version.cc\n+++ b/libstdc++-v3/testsuite/20_util/optional/version.cc\n@@ -9,8 +9,10 @@\n # error \"Feature test macro for optional has wrong value for C++17 in <version>\"\n #elif __cplusplus == 202002L && __cpp_lib_optional != 202106L\n # error \"Feature test macro for optional has wrong value for C++20 in <version>\"\n-#elif __cplusplus > 202002L && __cpp_lib_optional != 202110L\n+#elif __cplusplus == 202302L && __cpp_lib_optional != 202110L\n # error \"Feature test macro for optional has wrong value for C++23 in <version>\"\n+#elif __cplusplus > 202302L && __cpp_lib_optional != 202505L\n+# error \"Feature test macro for optional has wrong value for C++26 in <version>\"\n #endif\n \n #if __cplusplus >= 202302L\n","prefixes":["v1","1/1"]}