[PATCH 1/2] libstdc++: Extract optional<T&> specialization to bits/optional_ref.h.

Jonathan Wakely jwakely@redhat.com
Fri Jul 3 11:44:27 GMT 2026


On Thu, 02 Jul 2026 at 14:22 +0200, Tomasz Kamiński wrote:
>This patch extracts optional<_Tp&> specialization to the new
>bits/optional_ref.h file. This allows it to be used as return
>type of exception_ptr_cast (as required by P3981R2) from <exception>,
>without introducing cyclic dependency.
>
>In addition to reference specialization, the definitions of
>nullopt_t, nullopt, __is_valid_contained_type..., and _Optional_func
>required for it are moved to this new file. We also forward declare
>__gnu_cxx::__normal_iterator required for iterator type defintion.
>
>To minimize set of dependencies, the following methods remain
>defined (now out of line) in <optional> header:
> * value - requires __throw_bad_optional_access
> * begin/end - requires __normal_iterator
> * then, or_else, transform, constructor from _Optional_func
>   - depends on invoke
> * value_or - moved for consistency
>Furthemore, to avoid introduction of dependency of <concepts>,
>the requires clause for or_else is changed from invocable<_Fn>
>to is_invocable_v<_Fn>. The is conforming, as standard specifies
>the former in Constraints, and user cannot really on subsumption.
>
>Finally, the in_place_t (and other tags) are extracted into separate
>bits/inplace_tags.h header, removing the dependency on bist/utility.h.

bist -> bits

>
>libstdc++-v3/ChangeLog:
>
>	* include/Makefile.am (bits/optional_ref.h): Add.
>	* include/Makefile.in: Regenerate.
>	* include/bits/inplace_tags.h: New file.
>	* include/bits/utility.h (std::in_place_t, std::in_place)
>	(std::in_place_type_t, std::in_place_type)
>	(std::in_place_index_t, in_place_index): Move to
>	bits/inplace_tags.h.
>	* include/bits/optional_ref.h: New file.
>	* include/std/optional (std::nullopt_t, std::nullopt)
>	(std::__is_valid_contained_type_for_optional)
>	(std::_Optional_func, std::optional<_Tp&>)
>	(std::__is_optional_ref_v, std::__optional_ref_base):
>	Moved to bits/optional_ref.h.
>	(optional<_Tp&>::begin, optional<_Tp&>::end)
>	(optional<_Tp&>::value, optional<_Tp&>::value_or)
>	(optional<_Tp&>::and_then, optional<_Tp&>::transform)
>	(optional<_Tp&>::optional(_Optional_func<_Fn>, _Value):
>	Define out of line.
>	(optional<_Tp&>::or_else): Define out of line, and
>	change requires from invocable<_Fn> to is_invocable_v<_Fn>.
>---
>Testing on x86_64-linux. All test passed locally.
>OK for trunk when exteded suite happens?
>
> libstdc++-v3/include/Makefile.am         |   2 +
> libstdc++-v3/include/Makefile.in         |   2 +
> libstdc++-v3/include/bits/inplace_tags.h |  84 +++++
> libstdc++-v3/include/bits/optional_ref.h | 389 ++++++++++++++++++++++
> libstdc++-v3/include/bits/utility.h      |  39 +--
> libstdc++-v3/include/std/optional        | 405 ++++-------------------
> 6 files changed, 545 insertions(+), 376 deletions(-)
> create mode 100644 libstdc++-v3/include/bits/inplace_tags.h
> create mode 100644 libstdc++-v3/include/bits/optional_ref.h
>
>diff --git a/libstdc++-v3/include/Makefile.am b/libstdc++-v3/include/Makefile.am
>index f91a93ae4aa..262ba42950b 100644
>--- a/libstdc++-v3/include/Makefile.am
>+++ b/libstdc++-v3/include/Makefile.am
>@@ -138,6 +138,7 @@ bits_freestanding = \
> 	${bits_srcdir}/enable_special_members.h \
> 	${bits_srcdir}/functexcept.h \
> 	${bits_srcdir}/functional_hash.h \
>+	${bits_srcdir}/inplace_tags.h \
> 	${bits_srcdir}/intcmp.h \
> 	${bits_srcdir}/invoke.h \
> 	${bits_srcdir}/iosfwd.h \
>@@ -152,6 +153,7 @@ bits_freestanding = \
> 	${bits_srcdir}/memoryfwd.h \
> 	${bits_srcdir}/monostate.h \
> 	${bits_srcdir}/move.h \
>+	${bits_srcdir}/optional_ref.h \
> 	${bits_srcdir}/ostream.h \
> 	${bits_srcdir}/out_ptr.h \
> 	${bits_srcdir}/predefined_ops.h \
>diff --git a/libstdc++-v3/include/Makefile.in b/libstdc++-v3/include/Makefile.in
>index 611ef30c6cd..0d97a5acdb2 100644
>--- a/libstdc++-v3/include/Makefile.in
>+++ b/libstdc++-v3/include/Makefile.in
>@@ -496,6 +496,7 @@ bits_freestanding = \
> 	${bits_srcdir}/enable_special_members.h \
> 	${bits_srcdir}/functexcept.h \
> 	${bits_srcdir}/functional_hash.h \
>+	${bits_srcdir}/inplace_tags.h \
> 	${bits_srcdir}/intcmp.h \
> 	${bits_srcdir}/invoke.h \
> 	${bits_srcdir}/iosfwd.h \
>@@ -510,6 +511,7 @@ bits_freestanding = \
> 	${bits_srcdir}/memoryfwd.h \
> 	${bits_srcdir}/monostate.h \
> 	${bits_srcdir}/move.h \
>+	${bits_srcdir}/optional_ref.h \
> 	${bits_srcdir}/ostream.h \
> 	${bits_srcdir}/out_ptr.h \
> 	${bits_srcdir}/predefined_ops.h \
>diff --git a/libstdc++-v3/include/bits/inplace_tags.h b/libstdc++-v3/include/bits/inplace_tags.h
>new file mode 100644
>index 00000000000..c6c1f762c61
>--- /dev/null
>+++ b/libstdc++-v3/include/bits/inplace_tags.h
>@@ -0,0 +1,84 @@
>+// Tag types for inplace construction. -*- C++ -*-
>+
>+// Copyright (C) 2004-2026 Free Software Foundation, Inc.
>+//
>+// This file is part of the GNU ISO C++ Library.  This library is free
>+// software; you can redistribute it and/or modify it under the
>+// terms of the GNU General Public License as published by the
>+// Free Software Foundation; either version 3, or (at your option)
>+// any later version.
>+
>+// This library is distributed in the hope that it will be useful,
>+// but WITHOUT ANY WARRANTY; without even the implied warranty of
>+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>+// GNU General Public License for more details.
>+
>+// Under Section 7 of GPL version 3, you are granted additional
>+// permissions described in the GCC Runtime Library Exception, version
>+// 3.1, as published by the Free Software Foundation.
>+
>+// You should have received a copy of the GNU General Public License and
>+// a copy of the GCC Runtime Library Exception along with this program;
>+// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
>+// <http://www.gnu.org/licenses/>.
>+
>+/** @file include/bits/inplace_tags.h
>+ *  This is an internal header file, included by other library headers.
>+ *  Do not attempt to use it directly. @headername{utility}
>+ *
>+ *  This file contains the parts of `<utility>` needed by other headers,
>+ *  so they don't need to include the whole of `<utility>`.
>+ */
>+
>+#ifndef _GLIBCXX_INPLACE_TAGS_H
>+#define _GLIBCXX_INPLACE_TAGS_H 1
>+
>+#ifdef _GLIBCXX_SYSHDR
>+#pragma GCC system_header
>+#endif
>+
>+#if __cplusplus >= 201703L
>+
>+namespace std _GLIBCXX_VISIBILITY(default)
>+{
>+_GLIBCXX_BEGIN_NAMESPACE_VERSION
>+
>+  struct in_place_t {
>+    explicit in_place_t() = default;
>+  };
>+
>+  inline constexpr in_place_t in_place{};
>+
>+  template<typename _Tp> struct in_place_type_t
>+  {
>+    explicit in_place_type_t() = default;
>+  };
>+
>+  template<typename _Tp>
>+    inline constexpr in_place_type_t<_Tp> in_place_type{};
>+
>+  template<size_t _Idx> struct in_place_index_t
>+  {
>+    explicit in_place_index_t() = default;
>+  };
>+
>+  template<size_t _Idx>
>+    inline constexpr in_place_index_t<_Idx> in_place_index{};
>+
>+  template<typename>
>+    inline constexpr bool __is_in_place_type_v = false;
>+
>+  template<typename _Tp>
>+    inline constexpr bool __is_in_place_type_v<in_place_type_t<_Tp>> = true;
>+
>+  template<typename>
>+    inline constexpr bool __is_in_place_index_v = false;
>+
>+  template<size_t _Nm>
>+    inline constexpr bool __is_in_place_index_v<in_place_index_t<_Nm>> = true;
>+
>+_GLIBCXX_END_NAMESPACE_VERSION
>+} // namespace
>+
>+#endif // C++17
>+#endif /* _GLIBCXX_INPLACE_TAGS_H */
>diff --git a/libstdc++-v3/include/bits/optional_ref.h b/libstdc++-v3/include/bits/optional_ref.h
>new file mode 100644
>index 00000000000..e018a4199e9
>--- /dev/null
>+++ b/libstdc++-v3/include/bits/optional_ref.h
>@@ -0,0 +1,389 @@
>+// optional<T&> -*- C++ -*-
>+
>+// Copyright (C) 2013-2026 Free Software Foundation, Inc.
>+// Copyright The GNU Toolchain Authors.
>+//
>+// This file is part of the GNU ISO C++ Library.  This library is free
>+// software; you can redistribute it and/or modify it under the
>+// terms of the GNU General Public License as published by the
>+// Free Software Foundation; either version 3, or (at your option)
>+// any later version.
>+
>+// This library is distributed in the hope that it will be useful,
>+// but WITHOUT ANY WARRANTY; without even the implied warranty of
>+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>+// GNU General Public License for more details.
>+
>+// Under Section 7 of GPL version 3, you are granted additional
>+// permissions described in the GCC Runtime Library Exception, version
>+// 3.1, as published by the Free Software Foundation.
>+
>+// You should have received a copy of the GNU General Public License and
>+// a copy of the GCC Runtime Library Exception along with this program;
>+// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
>+// <http://www.gnu.org/licenses/>.
>+
>+/** @file include/optional
>+ *  This is a tandard C++ Library header.

No it isn't :-)
This comment block should be removed, the @file block below is
correct.


OK with that change

>+ */
>+
>+/** @file bits/optional_ref.h
>+ *  This is an internal header file, included by other library headers.
>+ *  Do not attempt to use it directly. @headername{optional}
>+ */
>+
>+#ifndef _GLIBCXX_OPTIONAL_REF
>+#define _GLIBCXX_OPTIONAL_REF 1
>+
>+#ifdef _GLIBCXX_SYSHDR
>+#pragma GCC system_header
>+#endif
>+
>+#ifdef __glibcxx_optional // C++ >= 17
>+
>+#include <type_traits>
>+#include <bits/move.h>
>+#include <bits/inplace_tags.h>
>+
>+namespace __gnu_cxx _GLIBCXX_VISIBILITY(default)
>+{
>+_GLIBCXX_BEGIN_NAMESPACE_VERSION
>+
>+  template<typename _Iterator, typename _Container>
>+    class __normal_iterator;
>+
>+_GLIBCXX_END_NAMESPACE_VERSION
>+} // namespace __gnu_cxx
>+
>+namespace std _GLIBCXX_VISIBILITY(default)
>+{
>+_GLIBCXX_BEGIN_NAMESPACE_VERSION
>+
>+   /**
>+   *  @addtogroup utilities
>+   *  @{
>+   */
>+
>+  template<typename _Tp>
>+    class optional;
>+
>+  /// Tag type to disengage optional objects.
>+  struct nullopt_t
>+  {
>+    // Do not user-declare default constructor at all for
>+    // optional_value = {} syntax to work.
>+    // nullopt_t() = delete;
>+
>+    // Used for constructing nullopt.
>+    enum class _Construct { _Token };
>+
>+    // Must be constexpr for nullopt_t to be literal.
>+    explicit constexpr nullopt_t(_Construct) noexcept { }
>+  };
>+
>+  /// Tag to disengage optional objects.
>+  inline constexpr nullopt_t nullopt { nullopt_t::_Construct::_Token };
>+
>+  template<typename _Fn> struct _Optional_func { _Fn& _M_f; };
>+
>+  template<typename _Tp>
>+    inline constexpr bool __is_valid_contained_type_for_optional =
>+      (
>+#if __glibcxx_optional >= 202506L
>+	is_lvalue_reference_v<_Tp> ||
>+#endif
>+	(is_object_v<_Tp> && is_destructible_v<_Tp> && !is_array_v<_Tp>)
>+      )
>+      && !is_same_v<remove_cv_t<remove_reference_t<_Tp>>, nullopt_t>
>+      && !is_same_v<remove_cv_t<remove_reference_t<_Tp>>, in_place_t>;
>+
>+#if __glibcxx_optional >= 202506L // C++26
>+  template<typename _Tp>
>+    class optional<_Tp&>;
>+
>+  template<typename _Tp>
>+    constexpr bool __is_optional_ref_v = false;
>+
>+  template<typename _Tp>
>+    constexpr bool __is_optional_ref_v<optional<_Tp&>> = true;
>+
>+  template<typename _Tp>
>+    struct __optional_ref_base
>+    {};
>+
>+#ifdef __glibcxx_optional_range_support // >= C++26
>+  template<typename _Tp>
>+    struct __optional_ref_base<_Tp[]>
>+    {};
>+
>+  template<typename _Tp>
>+    requires is_object_v<_Tp>
>+    struct __optional_ref_base<_Tp>
>+    {
>+      using iterator = __gnu_cxx::__normal_iterator<_Tp*, optional<_Tp&>>;
>+    };
>+#endif // __glibcxx_optional_range_support
>+
>+  template<typename _Tp>
>+    class optional<_Tp&> : public __optional_ref_base<_Tp>
>+    {
>+      static_assert(__is_valid_contained_type_for_optional<_Tp&>);
>+
>+    public:
>+      using value_type = _Tp;
>+
>+      // Constructors.
>+      constexpr optional() noexcept = default;
>+      constexpr optional(nullopt_t) noexcept : optional() {}
>+      constexpr optional(const optional&) noexcept = default;
>+
>+      template<typename _Arg>
>+	requires is_constructible_v<_Tp&, _Arg>
>+	  && (!reference_constructs_from_temporary_v<_Tp&, _Arg>)
>+	explicit constexpr
>+	optional(in_place_t, _Arg&& __arg)
>+	{
>+	  __convert_ref_init_val(std::forward<_Arg>(__arg));
>+	}
>+
>+      template<typename _Up>
>+	requires (!is_same_v<remove_cvref_t<_Up>, optional>)
>+	  && (!is_same_v<remove_cvref_t<_Up>, in_place_t>)
>+	  && is_constructible_v<_Tp&, _Up>
>+	  && (!reference_constructs_from_temporary_v<_Tp&, _Up>)
>+	explicit(!is_convertible_v<_Up, _Tp&>)
>+	constexpr
>+	optional(_Up&& __u)
>+	noexcept(is_nothrow_constructible_v<_Tp&, _Up>)
>+	{
>+	  __convert_ref_init_val(std::forward<_Up>(__u));
>+	}
>+
>+      template<typename _Up>
>+	requires (!is_same_v<remove_cvref_t<_Up>, optional>)
>+	  && (!is_same_v<remove_cvref_t<_Up>, in_place_t>)
>+	  && is_constructible_v<_Tp&, _Up>
>+	  && reference_constructs_from_temporary_v<_Tp&, _Up>
>+	explicit(!is_convertible_v<_Up, _Tp&>)
>+	constexpr
>+	optional(_Up&& __u) = delete;
>+
>+      // optional<U> &
>+      template<typename _Up>
>+	requires (!is_same_v<remove_cv_t<_Tp>, optional<_Up>>)
>+	  && (!is_same_v<_Tp&, _Up>)
>+	  && is_constructible_v<_Tp&, _Up&>
>+	  && (!reference_constructs_from_temporary_v<_Tp&, _Up&>)
>+	explicit(!is_convertible_v<_Up&, _Tp&>)
>+	constexpr
>+	optional(optional<_Up>& __rhs)
>+	noexcept(is_nothrow_constructible_v<_Tp&, _Up&>)
>+	{
>+	  if (__rhs)
>+	    __convert_ref_init_val(__rhs._M_fwd());
>+	}
>+
>+      template<typename _Up>
>+	requires (!is_same_v<remove_cv_t<_Tp>, optional<_Up>>)
>+	  && (!is_same_v<_Tp&, _Up>)
>+	  && is_constructible_v<_Tp&, _Up&>
>+	  && reference_constructs_from_temporary_v<_Tp&, _Up&>
>+	explicit(!is_convertible_v<_Up&, _Tp&>)
>+	constexpr
>+	optional(optional<_Up>& __rhs) = delete;
>+
>+      // const optional<U>&
>+      template<typename _Up>
>+	requires (!is_same_v<remove_cv_t<_Tp>, optional<_Up>>)
>+	  && (!is_same_v<_Tp&, _Up>)
>+	  && is_constructible_v<_Tp&, const _Up&>
>+	  && (!reference_constructs_from_temporary_v<_Tp&, const _Up&>)
>+	explicit(!is_convertible_v<const _Up&, _Tp&>)
>+	constexpr
>+	optional(const optional<_Up>& __rhs)
>+	noexcept(is_nothrow_constructible_v<_Tp&, _Up&>)
>+	{
>+	  if (__rhs)
>+	    __convert_ref_init_val(__rhs._M_fwd());
>+	}
>+
>+      template<typename _Up>
>+	requires (!is_same_v<remove_cv_t<_Tp>, optional<_Up>>)
>+	  && (!is_same_v<_Tp&, _Up>)
>+	  && is_constructible_v<_Tp&, const _Up&>
>+	  && reference_constructs_from_temporary_v<_Tp&, const _Up&>
>+	explicit(!is_convertible_v<const _Up&, _Tp&>)
>+	constexpr
>+	optional(const optional<_Up>& __rhs) = delete;
>+
>+      // optional<U>&&
>+      template<typename _Up>
>+	requires (!is_same_v<remove_cv_t<_Tp>, optional<_Up>>)
>+	  && (!is_same_v<_Tp&, _Up>)
>+	  && is_constructible_v<_Tp&, _Up>
>+	  && (!reference_constructs_from_temporary_v<_Tp&, _Up>)
>+	explicit(!is_convertible_v<_Up, _Tp&>)
>+	constexpr
>+	optional(optional<_Up>&& __rhs)
>+	noexcept(is_nothrow_constructible_v<_Tp&, _Up>)
>+	{
>+	  if (__rhs)
>+	    __convert_ref_init_val(std::move(__rhs)._M_fwd());
>+	}
>+
>+      template<typename _Up>
>+	requires (!is_same_v<remove_cv_t<_Tp>, optional<_Up>>)
>+	  && (!is_same_v<_Tp&, _Up>)
>+	  && is_constructible_v<_Tp&, _Up>
>+	  && reference_constructs_from_temporary_v<_Tp&, _Up>
>+	explicit(!is_convertible_v<_Up, _Tp&>)
>+	constexpr
>+	optional(optional<_Up>&& __rhs) = delete;
>+
>+      // const optional<U>&&
>+      template<typename _Up>
>+	requires (!is_same_v<remove_cv_t<_Tp>, optional<_Up>>)
>+	  && (!is_same_v<_Tp&, _Up>)
>+	  && is_constructible_v<_Tp&, const _Up>
>+	  && (!reference_constructs_from_temporary_v<_Tp&, _Up>)
>+	explicit(!is_convertible_v<const _Up, _Tp&>)
>+	constexpr
>+	optional(const optional<_Up>&& __rhs)
>+	noexcept(is_nothrow_constructible_v<_Tp&, const _Up>)
>+	{
>+	  if (__rhs)
>+	    __convert_ref_init_val(std::move(__rhs)._M_fwd());
>+	}
>+
>+      template<typename _Up>
>+	requires (!is_same_v<remove_cv_t<_Tp>, optional<_Up>>)
>+	  && (!is_same_v<_Tp&, _Up>)
>+	  && is_constructible_v<_Tp&, const _Up>
>+	  && reference_constructs_from_temporary_v<_Tp&, const _Up>
>+	explicit(!is_convertible_v<const _Up, _Tp&>)
>+	constexpr
>+	optional(const optional<_Up>&& __rhs) = delete;
>+
>+      constexpr ~optional() = default;
>+
>+      // Assignment.
>+      constexpr optional& operator=(nullopt_t) noexcept
>+      {
>+	_M_val = nullptr;
>+	return *this;
>+      }
>+
>+      constexpr optional& operator=(const optional&) noexcept = default;
>+
>+      template<typename _Up>
>+	requires is_constructible_v<_Tp&, _Up>
>+	  && (!reference_constructs_from_temporary_v<_Tp&, _Up>)
>+	constexpr _Tp&
>+	emplace(_Up&& __u)
>+	noexcept(is_nothrow_constructible_v<_Tp&, _Up>)
>+	{
>+	  __convert_ref_init_val(std::forward<_Up>(__u));
>+	  // _GLIBCXX_RESOLVE_LIB_DEFECTS
>+	  // 4300. Missing Returns: element in optional<T&>::emplace
>+	  return *_M_val;
>+	}
>+
>+      // Swap.
>+      constexpr void swap(optional& __rhs) noexcept
>+      { std::swap(_M_val, __rhs._M_val); }
>+
>+#ifdef __glibcxx_optional_range_support // >= C++26
>+      // Iterator support.
>+      constexpr auto begin() const noexcept
>+	requires is_object_v<_Tp> && (!is_unbounded_array_v<_Tp>);
>+
>+      constexpr auto end() const noexcept
>+	requires is_object_v<_Tp> && (!is_unbounded_array_v<_Tp>);
>+#endif // __glibcxx_optional_range_support
>+
>+      // Observers.
>+      constexpr _Tp* operator->() const noexcept
>+      {
>+	__glibcxx_assert(_M_val); // hardened precondition
>+	return _M_val;
>+      }
>+
>+      constexpr _Tp& operator*() const noexcept
>+      {
>+	__glibcxx_assert(_M_val); // hardened precondition
>+	return *_M_val;
>+      }
>+
>+      constexpr explicit operator bool() const noexcept
>+      {
>+	return _M_val;
>+      }
>+
>+      constexpr bool has_value() const noexcept
>+      {
>+	return _M_val;
>+      }
>+
>+      constexpr _Tp& value() const;
>+
>+      // _GLIBCXX_RESOLVE_LIB_DEFECTS
>+      // 4304. std::optional<NonReturnable&> is ill-formed due to value_or
>+      template<typename _Up = remove_cv_t<_Tp>>
>+	requires is_object_v<_Tp> && (!is_array_v<_Tp>)
>+	constexpr decay_t<_Tp>
>+	value_or(_Up&& __u) const;
>+
>+      // Monadic operations.
>+      template<typename _Fn>
>+	constexpr auto
>+	and_then(_Fn&& __f) const;
>+
>+      template<typename _Fn>
>+	constexpr
>+	optional<remove_cv_t<invoke_result_t<_Fn, _Tp&>>>
>+	transform(_Fn&& __f) const;
>+
>+      template<typename _Fn>
>+	requires is_invocable_v<_Fn>
>+	constexpr
>+	optional
>+	or_else(_Fn&& __f) const;
>+
>+      // Modifiers.
>+      constexpr void reset() noexcept
>+      {
>+	_M_val = nullptr;
>+      }
>+
>+    private:
>+      _Tp *_M_val = nullptr;
>+
>+      [[__gnu__::__always_inline__]]
>+      constexpr _Tp&
>+      _M_fwd() const noexcept
>+      { return *_M_val; }
>+
>+      template<typename _Up> friend class optional;
>+
>+      template<typename _Up>
>+	constexpr
>+	void
>+	__convert_ref_init_val(_Up&& __u)
>+	noexcept
>+	{
>+	  _Tp& __r(std::forward<_Up>(__u));
>+	  _M_val = std::addressof(__r);
>+	}
>+
>+      template<typename _Fn, typename _Value>
>+	explicit constexpr
>+	optional(_Optional_func<_Fn> __f, _Value&& __v);
>+    };
>+#endif // __glibcxx_optional >= 202506L
>+
>+_GLIBCXX_END_NAMESPACE_VERSION
>+} // namespace std
>+
>+#endif // __glibcxx_optional
>+
>+#endif // _GLIBCXX_OPTIONAL_REF
>diff --git a/libstdc++-v3/include/bits/utility.h b/libstdc++-v3/include/bits/utility.h
>index 320dd507b43..f3e956f33f9 100644
>--- a/libstdc++-v3/include/bits/utility.h
>+++ b/libstdc++-v3/include/bits/utility.h
>@@ -41,6 +41,7 @@
>
> #include <type_traits>
> #include <bits/move.h>
>+#include <bits/inplace_tags.h>
> #ifdef __glibcxx_constant_wrapper // C++ >= 26
> #  include <bits/invoke.h>
> #endif
>@@ -549,44 +550,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> #endif // __integer_pack
> #endif // __cpp_structured_bindings >= 202411L
>
>-#if __cplusplus >= 201703L
>-
>-  struct in_place_t {
>-    explicit in_place_t() = default;
>-  };
>-
>-  inline constexpr in_place_t in_place{};
>-
>-  template<typename _Tp> struct in_place_type_t
>-  {
>-    explicit in_place_type_t() = default;
>-  };
>-
>-  template<typename _Tp>
>-    inline constexpr in_place_type_t<_Tp> in_place_type{};
>-
>-  template<size_t _Idx> struct in_place_index_t
>-  {
>-    explicit in_place_index_t() = default;
>-  };
>-
>-  template<size_t _Idx>
>-    inline constexpr in_place_index_t<_Idx> in_place_index{};
>-
>-  template<typename>
>-    inline constexpr bool __is_in_place_type_v = false;
>-
>-  template<typename _Tp>
>-    inline constexpr bool __is_in_place_type_v<in_place_type_t<_Tp>> = true;
>-
>-  template<typename>
>-    inline constexpr bool __is_in_place_index_v = false;
>-
>-  template<size_t _Nm>
>-    inline constexpr bool __is_in_place_index_v<in_place_index_t<_Nm>> = true;
>-
>-#endif // C++17
>-
> #if _GLIBCXX_USE_BUILTIN_TRAIT(__type_pack_element)
>   template<size_t _Np, typename... _Types>
>     struct _Nth_type
>diff --git a/libstdc++-v3/include/std/optional b/libstdc++-v3/include/std/optional
>index 221beb2446d..d6fd33e8c2e 100644
>--- a/libstdc++-v3/include/std/optional
>+++ b/libstdc++-v3/include/std/optional
>@@ -51,6 +51,7 @@
> #include <bits/enable_special_members.h>
> #include <bits/exception_defines.h>
> #include <bits/functional_hash.h>
>+#include <bits/optional_ref.h>  // nullopt_t, optional<_Tp&>
> #include <bits/stl_construct.h> // _Construct
> #include <bits/utility.h> // in_place_t
> #if __cplusplus > 201703L
>@@ -77,28 +78,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>    *  @{
>    */
>
>-  template<typename _Tp>
>-    class optional;
>-
>-  /// Tag type to disengage optional objects.
>-  struct nullopt_t
>-  {
>-    // Do not user-declare default constructor at all for
>-    // optional_value = {} syntax to work.
>-    // nullopt_t() = delete;
>-
>-    // Used for constructing nullopt.
>-    enum class _Construct { _Token };
>-
>-    // Must be constexpr for nullopt_t to be literal.
>-    explicit constexpr nullopt_t(_Construct) noexcept { }
>-  };
>-
>-  /// Tag to disengage optional objects.
>-  inline constexpr nullopt_t nullopt { nullopt_t::_Construct::_Token };
>-
>-  template<typename _Fn> struct _Optional_func { _Fn& _M_f; };
>-
>   /**
>    *  @brief Exception class thrown when a disengaged optional object is
>    *  dereferenced.
>@@ -795,17 +774,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> # define _GLIBCXX_USE_CONSTRAINTS_FOR_OPTIONAL 1
> #endif
>
>-  template<typename _Tp>
>-    inline constexpr bool __is_valid_contained_type_for_optional =
>-      (
>-#if __cpp_lib_optional >= 202506L
>-	is_lvalue_reference_v<_Tp> ||
>-#endif
>-	(is_object_v<_Tp> && is_destructible_v<_Tp> && !is_array_v<_Tp>)
>-      )
>-      && !is_same_v<remove_cv_t<remove_reference_t<_Tp>>, nullopt_t>
>-      && !is_same_v<remove_cv_t<remove_reference_t<_Tp>>, in_place_t>;
>-
>   /**
>     * @brief Class template for optional values.
>     */
>@@ -1505,334 +1473,95 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>     };
>
> #if __cpp_lib_optional >= 202506L // C++26
>+#ifdef __cpp_lib_optional_range_support
>   template<typename _Tp>
>-    class optional<_Tp&>;
>-
>-  template<typename _Tp>
>-    constexpr bool __is_optional_ref_v = false;
>-
>-  template<typename _Tp>
>-    constexpr bool __is_optional_ref_v<optional<_Tp&>> = true;
>-
>-  template<typename _Tp>
>-    struct __optional_ref_base
>-    {};
>-
>-#ifdef __cpp_lib_optional_range_support // >= C++26
>-  template<typename _Tp>
>-    struct __optional_ref_base<_Tp[]>
>-    {};
>+    constexpr auto
>+    optional<_Tp&>::begin() const noexcept
>+      requires is_object_v<_Tp> && (!is_unbounded_array_v<_Tp>)
>+    { return __gnu_cxx::__normal_iterator<_Tp*, optional>(_M_val); }
>
>   template<typename _Tp>
>-    requires is_object_v<_Tp>
>-    struct __optional_ref_base<_Tp>
>-    {
>-      using iterator = __gnu_cxx::__normal_iterator<_Tp*, optional<_Tp&>>;
>-    };
>+    constexpr auto
>+    optional<_Tp&>::end() const noexcept
>+      requires is_object_v<_Tp> && (!is_unbounded_array_v<_Tp>)
>+    { return begin() + has_value(); }
> #endif // __cpp_lib_optional_range_support
>
>   template<typename _Tp>
>-    class optional<_Tp&> : public __optional_ref_base<_Tp>
>+    constexpr _Tp&
>+    optional<_Tp&>::value() const
>     {
>-      static_assert(__is_valid_contained_type_for_optional<_Tp&>);
>-
>-    public:
>-      using value_type = _Tp;
>-
>-      // Constructors.
>-      constexpr optional() noexcept = default;
>-      constexpr optional(nullopt_t) noexcept : optional() {}
>-      constexpr optional(const optional&) noexcept = default;
>-
>-      template<typename _Arg>
>-	requires is_constructible_v<_Tp&, _Arg>
>-	  && (!reference_constructs_from_temporary_v<_Tp&, _Arg>)
>-	explicit constexpr
>-	optional(in_place_t, _Arg&& __arg)
>-	{
>-	  __convert_ref_init_val(std::forward<_Arg>(__arg));
>-	}
>-
>-      template<typename _Up>
>-	requires (!is_same_v<remove_cvref_t<_Up>, optional>)
>-	  && (!is_same_v<remove_cvref_t<_Up>, in_place_t>)
>-	  && is_constructible_v<_Tp&, _Up>
>-	  && (!reference_constructs_from_temporary_v<_Tp&, _Up>)
>-	explicit(!is_convertible_v<_Up, _Tp&>)
>-	constexpr
>-	optional(_Up&& __u)
>-	noexcept(is_nothrow_constructible_v<_Tp&, _Up>)
>-	{
>-	  __convert_ref_init_val(std::forward<_Up>(__u));
>-	}
>-
>-      template<typename _Up>
>-	requires (!is_same_v<remove_cvref_t<_Up>, optional>)
>-	  && (!is_same_v<remove_cvref_t<_Up>, in_place_t>)
>-	  && is_constructible_v<_Tp&, _Up>
>-	  && reference_constructs_from_temporary_v<_Tp&, _Up>
>-	explicit(!is_convertible_v<_Up, _Tp&>)
>-	constexpr
>-	optional(_Up&& __u) = delete;
>-
>-      // optional<U> &
>-      template<typename _Up>
>-	requires (!is_same_v<remove_cv_t<_Tp>, optional<_Up>>)
>-	  && (!is_same_v<_Tp&, _Up>)
>-	  && is_constructible_v<_Tp&, _Up&>
>-	  && (!reference_constructs_from_temporary_v<_Tp&, _Up&>)
>-	explicit(!is_convertible_v<_Up&, _Tp&>)
>-	constexpr
>-	optional(optional<_Up>& __rhs)
>-	noexcept(is_nothrow_constructible_v<_Tp&, _Up&>)
>-	{
>-	  if (__rhs)
>-	    __convert_ref_init_val(__rhs._M_fwd());
>-	}
>-
>-      template<typename _Up>
>-	requires (!is_same_v<remove_cv_t<_Tp>, optional<_Up>>)
>-	  && (!is_same_v<_Tp&, _Up>)
>-	  && is_constructible_v<_Tp&, _Up&>
>-	  && reference_constructs_from_temporary_v<_Tp&, _Up&>
>-	explicit(!is_convertible_v<_Up&, _Tp&>)
>-	constexpr
>-	optional(optional<_Up>& __rhs) = delete;
>-
>-      // const optional<U>&
>-      template<typename _Up>
>-	requires (!is_same_v<remove_cv_t<_Tp>, optional<_Up>>)
>-	  && (!is_same_v<_Tp&, _Up>)
>-	  && is_constructible_v<_Tp&, const _Up&>
>-	  && (!reference_constructs_from_temporary_v<_Tp&, const _Up&>)
>-	explicit(!is_convertible_v<const _Up&, _Tp&>)
>-	constexpr
>-	optional(const optional<_Up>& __rhs)
>-	noexcept(is_nothrow_constructible_v<_Tp&, _Up&>)
>-	{
>-	  if (__rhs)
>-	    __convert_ref_init_val(__rhs._M_fwd());
>-	}
>-
>-      template<typename _Up>
>-	requires (!is_same_v<remove_cv_t<_Tp>, optional<_Up>>)
>-	  && (!is_same_v<_Tp&, _Up>)
>-	  && is_constructible_v<_Tp&, const _Up&>
>-	  && reference_constructs_from_temporary_v<_Tp&, const _Up&>
>-	explicit(!is_convertible_v<const _Up&, _Tp&>)
>-	constexpr
>-	optional(const optional<_Up>& __rhs) = delete;
>-
>-      // optional<U>&&
>-      template<typename _Up>
>-	requires (!is_same_v<remove_cv_t<_Tp>, optional<_Up>>)
>-	  && (!is_same_v<_Tp&, _Up>)
>-	  && is_constructible_v<_Tp&, _Up>
>-	  && (!reference_constructs_from_temporary_v<_Tp&, _Up>)
>-	explicit(!is_convertible_v<_Up, _Tp&>)
>-	constexpr
>-	optional(optional<_Up>&& __rhs)
>-	noexcept(is_nothrow_constructible_v<_Tp&, _Up>)
>-	{
>-	  if (__rhs)
>-	    __convert_ref_init_val(std::move(__rhs)._M_fwd());
>-	}
>-
>-      template<typename _Up>
>-	requires (!is_same_v<remove_cv_t<_Tp>, optional<_Up>>)
>-	  && (!is_same_v<_Tp&, _Up>)
>-	  && is_constructible_v<_Tp&, _Up>
>-	  && reference_constructs_from_temporary_v<_Tp&, _Up>
>-	explicit(!is_convertible_v<_Up, _Tp&>)
>-	constexpr
>-	optional(optional<_Up>&& __rhs) = delete;
>-
>-      // const optional<U>&&
>-      template<typename _Up>
>-	requires (!is_same_v<remove_cv_t<_Tp>, optional<_Up>>)
>-	  && (!is_same_v<_Tp&, _Up>)
>-	  && is_constructible_v<_Tp&, const _Up>
>-	  && (!reference_constructs_from_temporary_v<_Tp&, _Up>)
>-	explicit(!is_convertible_v<const _Up, _Tp&>)
>-	constexpr
>-	optional(const optional<_Up>&& __rhs)
>-	noexcept(is_nothrow_constructible_v<_Tp&, const _Up>)
>-	{
>-	  if (__rhs)
>-	    __convert_ref_init_val(std::move(__rhs)._M_fwd());
>-	}
>-
>-      template<typename _Up>
>-	requires (!is_same_v<remove_cv_t<_Tp>, optional<_Up>>)
>-	  && (!is_same_v<_Tp&, _Up>)
>-	  && is_constructible_v<_Tp&, const _Up>
>-	  && reference_constructs_from_temporary_v<_Tp&, const _Up>
>-	explicit(!is_convertible_v<const _Up, _Tp&>)
>-	constexpr
>-	optional(const optional<_Up>&& __rhs) = delete;
>-
>-      constexpr ~optional() = default;
>+      if (_M_val)
>+	return *_M_val;
>+      __throw_bad_optional_access();
>+    }
>
>-      // Assignment.
>-      constexpr optional& operator=(nullopt_t) noexcept
>+  template<typename _Tp>
>+    template<typename _Up>
>+      requires is_object_v<_Tp> && (!is_array_v<_Tp>)
>+      constexpr decay_t<_Tp>
>+      optional<_Tp&>::value_or(_Up&& __u) const
>       {
>-	_M_val = nullptr;
>-	return *this;
>-      }
>-
>-      constexpr optional& operator=(const optional&) noexcept = default;
>-
>-      template<typename _Up>
>-	requires is_constructible_v<_Tp&, _Up>
>-	  && (!reference_constructs_from_temporary_v<_Tp&, _Up>)
>-	constexpr _Tp&
>-	emplace(_Up&& __u)
>-	noexcept(is_nothrow_constructible_v<_Tp&, _Up>)
>-	{
>-	  __convert_ref_init_val(std::forward<_Up>(__u));
>-	  // _GLIBCXX_RESOLVE_LIB_DEFECTS
>-	  // 4300. Missing Returns: element in optional<T&>::emplace
>+	using _Xp = remove_cv_t<_Tp>;
>+	static_assert(is_convertible_v<_Tp&, _Xp>);
>+	static_assert(is_convertible_v<_Up, _Xp>);
>+	if (_M_val)
> 	  return *_M_val;
>-	}
>-
>-      // Swap.
>-      constexpr void swap(optional& __rhs) noexcept
>-      { std::swap(_M_val, __rhs._M_val); }
>-
>-#ifdef __cpp_lib_optional_range_support // >= C++26
>-      // Iterator support.
>-      constexpr auto begin() const noexcept
>-	requires is_object_v<_Tp> && (!is_unbounded_array_v<_Tp>)
>-      { return __gnu_cxx::__normal_iterator<_Tp*, optional>(_M_val); }
>-
>-      constexpr auto end() const noexcept
>-	requires is_object_v<_Tp> && (!is_unbounded_array_v<_Tp>)
>-      { return begin() + has_value(); }
>-#endif // __cpp_lib_optional_range_support
>-
>-      // Observers.
>-      constexpr _Tp* operator->() const noexcept
>-      {
>-	__glibcxx_assert(_M_val); // hardened precondition
>-	return _M_val;
>-      }
>-
>-      constexpr _Tp& operator*() const noexcept
>-      {
>-	__glibcxx_assert(_M_val); // hardened precondition
>-	return *_M_val;
>+	return std::forward<_Up>(__u);
>       }
>
>-      constexpr explicit operator bool() const noexcept
>+  template<typename _Tp>
>+    template<typename _Fn>
>+      constexpr auto
>+      optional<_Tp&>::and_then(_Fn&& __f) const
>       {
>-	return _M_val;
>+        using _Up = remove_cvref_t<invoke_result_t<_Fn, _Tp&>>;
>+        static_assert(__is_optional_v<_Up>,
>+                      "the function passed to std::optional<T&>::and_then "
>+                      "must return a std::optional");
>+        if (has_value())
>+          return std::__invoke(std::forward<_Fn>(__f), *_M_val);
>+        else
>+          return _Up();
>       }
>
>-      constexpr bool has_value() const noexcept
>+  template<typename _Tp>
>+    template<typename _Fn>
>+      constexpr optional<remove_cv_t<invoke_result_t<_Fn, _Tp&>>>
>+      optional<_Tp&>::transform(_Fn&& __f) const
>       {
>-	return _M_val;
>+        using _Up = remove_cv_t<invoke_result_t<_Fn, _Tp&>>;
>+        if (has_value())
>+          return optional<_Up>(_Optional_func<_Fn>{__f}, *_M_val);
>+        else
>+          return optional<_Up>();
>       }
>
>-      constexpr _Tp& value() const
>+  template<typename _Tp>
>+    template<typename _Fn>
>+      requires is_invocable_v<_Fn>
>+      constexpr optional<_Tp&>
>+      optional<_Tp&>::or_else(_Fn&& __f) const
>       {
>-	if (_M_val)
>-	  return *_M_val;
>-	__throw_bad_optional_access();
>+        static_assert(is_same_v<remove_cvref_t<invoke_result_t<_Fn>>, optional>,
>+                      "the function passed to std::optional<T&>::or_else "
>+                      "must return a std::optional<T&>");
>+        // _GLIBCXX_RESOLVE_LIB_DEFECTS
>+        // 4367. Improve optional<T&>::or_else
>+        if (has_value())
>+          return *this;
>+        else
>+          return std::forward<_Fn>(__f)();
>       }
>
>-      // _GLIBCXX_RESOLVE_LIB_DEFECTS
>-      // 4304. std::optional<NonReturnable&> is ill-formed due to value_or
>-      template<typename _Up = remove_cv_t<_Tp>>
>-	requires is_object_v<_Tp> && (!is_array_v<_Tp>)
>-	constexpr decay_t<_Tp>
>-	value_or(_Up&& __u) const
>-	{
>-	  using _Xp = remove_cv_t<_Tp>;
>-	  static_assert(is_convertible_v<_Tp&, _Xp>);
>-	  static_assert(is_convertible_v<_Up, _Xp>);
>-	  if (_M_val)
>-	    return *_M_val;
>-	  return std::forward<_Up>(__u);
>-	}
>-
>-      // Monadic operations.
>-      template<typename _Fn>
>-	constexpr auto
>-	and_then(_Fn&& __f) const
>-	{
>-	  using _Up = remove_cvref_t<invoke_result_t<_Fn, _Tp&>>;
>-	  static_assert(__is_optional_v<_Up>,
>-			"the function passed to std::optional<T&>::and_then "
>-			"must return a std::optional");
>-	  if (has_value())
>-	    return std::__invoke(std::forward<_Fn>(__f), *_M_val);
>-	  else
>-	    return _Up();
>-	}
>-
>-      template<typename _Fn>
>-	constexpr
>-	optional<remove_cv_t<invoke_result_t<_Fn, _Tp&>>>
>-	transform(_Fn&& __f) const
>-	{
>-	  using _Up = remove_cv_t<invoke_result_t<_Fn, _Tp&>>;
>-	  if (has_value())
>-	    return optional<_Up>(_Optional_func<_Fn>{__f}, *_M_val);
>-	  else
>-	    return optional<_Up>();
>-	}
>-
>-      template<typename _Fn>
>-	requires invocable<_Fn>
>-	constexpr
>-	optional
>-	or_else(_Fn&& __f) const
>-	{
>-	  static_assert(is_same_v<remove_cvref_t<invoke_result_t<_Fn>>, optional>,
>-			"the function passed to std::optional<T&>::or_else "
>-			"must return a std::optional<T&>");
>-	  // _GLIBCXX_RESOLVE_LIB_DEFECTS
>-	  // 4367. Improve optional<T&>::or_else
>-	  if (has_value())
>-	    return *this;
>-	  else
>-	    return std::forward<_Fn>(__f)();
>-	}
>-
>-      // Modifiers.
>-      constexpr void reset() noexcept
>+  template<typename _Tp>
>+    template<typename _Fn, typename _Value>
>+      constexpr
>+      optional<_Tp&>::optional(_Optional_func<_Fn> __f, _Value&& __v)
>       {
>-	_M_val = nullptr;
>+        _Tp& __r = std::__invoke(std::forward<_Fn>(__f._M_f), std::forward<_Value>(__v));
>+        _M_val = std::addressof(__r);
>       }
>-
>-    private:
>-      _Tp *_M_val = nullptr;
>-
>-      [[__gnu__::__always_inline__]]
>-      constexpr _Tp&
>-      _M_fwd() const noexcept
>-      { return *_M_val; }
>-
>-      template<typename _Up> friend class optional;
>-
>-      template<typename _Up>
>-	constexpr
>-	void
>-	__convert_ref_init_val(_Up&& __u)
>-	noexcept
>-	{
>-	  _Tp& __r(std::forward<_Up>(__u));
>-	  _M_val = std::addressof(__r);
>-	}
>-
>-      template<typename _Fn, typename _Value>
>-	explicit constexpr
>-	optional(_Optional_func<_Fn> __f, _Value&& __v)
>-	{
>-	  _Tp& __r = std::__invoke(std::forward<_Fn>(__f._M_f), std::forward<_Value>(__v));
>-	  _M_val = std::addressof(__r);
>-	}
>-    };
> #endif // __cpp_lib_optional >= 202506L
>
>   template<typename _Tp>
>-- 
>2.54.0
>
>



More information about the Libstdc++ mailing list