[PATCH 1/2] libstdc++: Implement optional<T&> from P2988R12 [PR121748]

Tomasz Kaminski tkaminsk@redhat.com
Mon Oct 20 08:05:28 GMT 2025


On Mon, Oct 20, 2025 at 10:01 AM Hewill Kang <hewillk@gmail.com> wrote:

> The delete constructor takes the *same* parameters as its non-delete
> counterpart. Instead of int and float.
> Could you give an example where this change actually makes
> `optional<T&>` ambiguous?
>
My point it, if I repeat the explicit, I do not need to think about proving
to myself that such an example does not exist.
If I would aim to look for it, I would look into a wrapper with conversion
to T and T&, where one is explicit. Or T& and T&&.

>
> Tomasz Kaminski <tkaminsk@redhat.com> 於 2025年10月20日 週一 下午3:49寫道:
>
>>
>>
>> On Fri, Oct 17, 2025 at 7:43 PM Hewill Kang <hewillk@gmail.com> wrote:
>>
>>> +      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;
>>>
>>>
>>> It seems that the above can be simplified to (without explicit and
>>> constexpr):
>>>
>> The explicit on delete is important, when implicit  conversions sequence
>> is format,
>> for example:
>> struct S {
>> explicit S(float) = delete;
>> S(int) { std::cout << "int" << std::endl; }
>> };
>>
>> void foo(S) {}
>>
>> int main() {
>> foo(10.0);
>> }
>> Removing explicit from S(float) will make the `foo(10.0)` call ill-formed
>> (ambiguous).
>> I am not 100% sure that constexpr is not observable, given the presence
>> of competing constructor.
>>
>>
>>>
>>> +      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>
>>> +       optional(_Up&& __u) = delete;
>>>
>>> And those
>>>
>>> +      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;
>>>
>>>
>>> can be simplified to:
>>>
>>> +      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&>
>>>> +       optional(optional<_Up>& __rhs) = delete;
>>>
>>>
>>> I have the impression that we use these simplified forms in tuples.
>>>
>> We may be then non-conforming in tuples.
>>
>>>
>>> Tomasz Kamiński <tkaminsk@redhat.com> 於 2025年10月17日 週五 下午11:18寫道:
>>>
>>>> From: Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
>>>>
>>>> This patch implements optional<T&> based on the P2988R12 paper,
>>>> incorporating
>>>> corrections for LWG4300, LWG4304, and LWG3467. The resolution for
>>>> LWG4015
>>>> is also extended to cover optional<T&>.
>>>>
>>>> In optional<T> use std::move(__t).operator*() to correctly propagate
>>>> the value
>>>> during move construction from optional<T&>. This is necessary because
>>>> moving
>>>> an optional<T&> must not move the contained object, which is the key
>>>> distinction
>>>> between *std::move(opt) and std::move(*opt).
>>>>
>>>> The implementation deviates from the standard by providing a separate
>>>> std::swap
>>>> overload for std::optional<T&>, which simplifies preserving the
>>>> resolution of
>>>> LWG2766.
>>>>
>>>> This introduces a few changes to make_optional behavior (see included
>>>> test):
>>>> * some previously valid uses of make_optional<T>({...}) (where T is not
>>>> a
>>>>   reference type) now become ill-formed (see
>>>> optional/make_optional_neg.cc).
>>>> * make_optional<T&>(t) and make_optional<const T&>(ct), where
>>>> decltype(t) is T&,
>>>>   and decltype(cy) is const T& now  produce optional<T&> and
>>>> optional<const T&>
>>>>   respectively, instead of optional<T>.
>>>> * a few other uses of make_optional<R> with reference types are now
>>>> ill-formed.
>>>>
>>>>         PR libstdc++/121748
>>>>
>>>> libstdc++-v3/ChangeLog:
>>>>
>>>>         * include/bits/version.def: Bump value for optional,
>>>>         * include/bits/version.h: Regenerate.
>>>>         * include/std/optional
>>>> (std::__is_valid_contained_type_for_optional):
>>>>         Define.
>>>>         (std::optional<T>): Use __is_valid_contained_type_for_optional.
>>>>         (optional<T>(const optional<_Up>&),
>>>> optional<T>(optional<_Up>&&))
>>>>         (optional<T>::operator=(const optional<_Up>&))
>>>>         (optional<T>::operator=(optional<_Up>&&)): Replace
>>>> std::move(x._M_get())
>>>>         with std::move(x).operator*(), and x._M_get() with
>>>> x.operator*().
>>>>         (optional<T>::and_then): Remove uncessary remove_cvref_t.
>>>>         (std::optional<T&>): Define new partial specialization.
>>>>         (std::swap(std::optional<T&>, std::optional<T&>)): Define.
>>>>         (std::make_optional(_Tp&&)): Add non-type template parameter.
>>>>         (std::make_optional): Use parenthesis to constructor optional.
>>>>         (std::hash<optional<T>>): Add comment.
>>>>         * testsuite/20_util/optional/make_optional-2.cc: Guarded not
>>>> longer
>>>>         working example.
>>>>         * testsuite/20_util/optional/relops/constrained.cc: Expand test
>>>> to
>>>>         cover optionals of reference.
>>>>         * testsuite/20_util/optional/requirements.cc: Ammend for
>>>> optional<T&>.
>>>>         * testsuite/20_util/optional/requirements_neg.cc: Likewise.
>>>>         * testsuite/20_util/optional/version.cc: Test new value of
>>>>         __cpp_lib_optional.
>>>>         * testsuite/20_util/optional/make_optional_neg.cc: New test.
>>>>         * testsuite/20_util/optional/monadic/ref_neg.cc: New test.
>>>>         * testsuite/20_util/optional/ref/access.cc: New test.
>>>>         * testsuite/20_util/optional/ref/assign.cc: New test.
>>>>         * testsuite/20_util/optional/ref/cons.cc: New test.
>>>>         * testsuite/20_util/optional/ref/internal_traits.cc: New test.
>>>>         * testsuite/20_util/optional/ref/make_optional/1.cc: New test.
>>>>         *
>>>> testsuite/20_util/optional/ref/make_optional/from_args_neg.cc: New test.
>>>>         *
>>>> testsuite/20_util/optional/ref/make_optional/from_lvalue_neg.cc: New test.
>>>>         *
>>>> testsuite/20_util/optional/ref/make_optional/from_rvalue_neg.cc: New test.
>>>>         * testsuite/20_util/optional/ref/monadic.cc: New test.
>>>>         * testsuite/20_util/optional/ref/relops.cc: New test.
>>>>
>>>> Co-authored-by: Tomasz Kamiński <tkaminsk@redhat.com>
>>>> ---
>>>> Tested on x86_64-linux locally. *optional* test also tested with all
>>>> standard modes.
>>>> OK for trunk?
>>>>
>>>>  libstdc++-v3/include/bits/version.def         |   8 +-
>>>>  libstdc++-v3/include/bits/version.h           |   7 +-
>>>>  libstdc++-v3/include/std/optional             | 360 ++++++++++++++-
>>>>  .../20_util/optional/make_optional-2.cc       |   2 +
>>>>  .../20_util/optional/make_optional_neg.cc     |  20 +
>>>>  .../20_util/optional/monadic/ref_neg.cc       |  20 +
>>>>  .../testsuite/20_util/optional/ref/access.cc  | 119 +++++
>>>>  .../testsuite/20_util/optional/ref/assign.cc  | 430 ++++++++++++++++++
>>>>  .../testsuite/20_util/optional/ref/cons.cc    | 356 +++++++++++++++
>>>>  .../20_util/optional/ref/internal_traits.cc   |  11 +
>>>>  .../20_util/optional/ref/make_optional/1.cc   |  74 +++
>>>>  .../ref/make_optional/from_args_neg.cc        |  43 ++
>>>>  .../ref/make_optional/from_lvalue_neg.cc      |  40 ++
>>>>  .../ref/make_optional/from_rvalue_neg.cc      |  38 ++
>>>>  .../testsuite/20_util/optional/ref/monadic.cc | 192 ++++++++
>>>>  .../testsuite/20_util/optional/ref/relops.cc  | 229 ++++++++++
>>>>  .../20_util/optional/relops/constrained.cc    |  86 +++-
>>>>  .../20_util/optional/requirements.cc          |   6 +-
>>>>  .../20_util/optional/requirements_neg.cc      |  17 +-
>>>>  .../testsuite/20_util/optional/version.cc     |   4 +-
>>>>  20 files changed, 2029 insertions(+), 33 deletions(-)
>>>>  create mode 100644
>>>> libstdc++-v3/testsuite/20_util/optional/make_optional_neg.cc
>>>>  create mode 100644
>>>> libstdc++-v3/testsuite/20_util/optional/monadic/ref_neg.cc
>>>>  create mode 100644
>>>> libstdc++-v3/testsuite/20_util/optional/ref/access.cc
>>>>  create mode 100644
>>>> libstdc++-v3/testsuite/20_util/optional/ref/assign.cc
>>>>  create mode 100644 libstdc++-v3/testsuite/20_util/optional/ref/cons.cc
>>>>  create mode 100644
>>>> libstdc++-v3/testsuite/20_util/optional/ref/internal_traits.cc
>>>>  create mode 100644
>>>> libstdc++-v3/testsuite/20_util/optional/ref/make_optional/1.cc
>>>>  create mode 100644
>>>> libstdc++-v3/testsuite/20_util/optional/ref/make_optional/from_args_neg.cc
>>>>  create mode 100644
>>>> libstdc++-v3/testsuite/20_util/optional/ref/make_optional/from_lvalue_neg.cc
>>>>  create mode 100644
>>>> libstdc++-v3/testsuite/20_util/optional/ref/make_optional/from_rvalue_neg.cc
>>>>  create mode 100644
>>>> libstdc++-v3/testsuite/20_util/optional/ref/monadic.cc
>>>>  create mode 100644
>>>> libstdc++-v3/testsuite/20_util/optional/ref/relops.cc
>>>>
>>>> diff --git a/libstdc++-v3/include/bits/version.def
>>>> b/libstdc++-v3/include/bits/version.def
>>>> index 1118da4b541..be15442a50f 100644
>>>> --- a/libstdc++-v3/include/bits/version.def
>>>> +++ b/libstdc++-v3/include/bits/version.def
>>>> @@ -878,12 +878,16 @@ ftms = {
>>>>  // Moved down here (after concepts) by topological sort.
>>>>  ftms = {
>>>>    name = optional;
>>>> -  values = {
>>>> +  values = { // optional<T&>
>>>> +    v = 202506;
>>>> +    cxxmin = 26;
>>>> +  };
>>>> +  values = { // monadic operations
>>>>      v = 202110;
>>>>      cxxmin = 23;
>>>>      extra_cond = "__glibcxx_concepts";
>>>>    };
>>>> -  values = {
>>>> +  values = { // full constexpr support
>>>>      v = 202106;
>>>>      cxxmin = 20;
>>>>    };
>>>> diff --git a/libstdc++-v3/include/bits/version.h
>>>> b/libstdc++-v3/include/bits/version.h
>>>> index c452bbeec8e..e98ecdf94e7 100644
>>>> --- a/libstdc++-v3/include/bits/version.h
>>>> +++ b/libstdc++-v3/include/bits/version.h
>>>> @@ -985,7 +985,12 @@
>>>>  #undef __glibcxx_want_concepts
>>>>
>>>>  #if !defined(__cpp_lib_optional)
>>>> -# if (__cplusplus >= 202100L) && (__glibcxx_concepts)
>>>> +# if (__cplusplus >  202302L)
>>>> +#  define __glibcxx_optional 202506L
>>>> +#  if defined(__glibcxx_want_all) || defined(__glibcxx_want_optional)
>>>> +#   define __cpp_lib_optional 202506L
>>>> +#  endif
>>>> +# elif (__cplusplus >= 202100L) && (__glibcxx_concepts)
>>>>  #  define __glibcxx_optional 202110L
>>>>  #  if defined(__glibcxx_want_all) || defined(__glibcxx_want_optional)
>>>>  #   define __cpp_lib_optional 202110L
>>>> diff --git a/libstdc++-v3/include/std/optional
>>>> b/libstdc++-v3/include/std/optional
>>>> index e5051d72c82..e6f3a985f50 100644
>>>> --- a/libstdc++-v3/include/std/optional
>>>> +++ b/libstdc++-v3/include/std/optional
>>>> @@ -777,6 +777,17 @@ _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.
>>>>      */
>>>> @@ -795,9 +806,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>>>>         // Unique tag type.
>>>>         optional<_Tp>>
>>>>      {
>>>> -      static_assert(!is_same_v<remove_cv_t<_Tp>, nullopt_t>);
>>>> -      static_assert(!is_same_v<remove_cv_t<_Tp>, in_place_t>);
>>>> -      static_assert(is_object_v<_Tp> && !is_array_v<_Tp>);
>>>> +      static_assert(__is_valid_contained_type_for_optional<_Tp>);
>>>>
>>>>      private:
>>>>        using _Base = _Optional_base<_Tp>;
>>>> @@ -894,7 +903,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>>>>         noexcept(is_nothrow_constructible_v<_Tp, const _Up&>)
>>>>         {
>>>>           if (__t)
>>>> -           emplace(__t._M_get());
>>>> +           emplace(__t.operator*());
>>>>         }
>>>>
>>>>        template<typename _Up>
>>>> @@ -906,7 +915,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>>>>         noexcept(is_nothrow_constructible_v<_Tp, _Up>)
>>>>         {
>>>>           if (__t)
>>>> -           emplace(std::move(__t._M_get()));
>>>> +           emplace(std::move(__t).operator*());
>>>>         }
>>>>
>>>>        template<typename... _Args>
>>>> @@ -956,7 +965,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>>>>         noexcept(is_nothrow_constructible_v<_Tp, const _Up&>)
>>>>         {
>>>>           if (__t)
>>>> -           emplace(__t._M_get());
>>>> +           emplace(__t.operator*());
>>>>         }
>>>>
>>>>        template<typename _Up,
>>>> @@ -969,7 +978,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>>>>         noexcept(is_nothrow_constructible_v<_Tp, const _Up&>)
>>>>         {
>>>>           if (__t)
>>>> -           emplace(__t._M_get());
>>>> +           emplace(__t.operator*());
>>>>         }
>>>>
>>>>        template<typename _Up,
>>>> @@ -982,7 +991,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>>>>         noexcept(is_nothrow_constructible_v<_Tp, _Up>)
>>>>         {
>>>>           if (__t)
>>>> -           emplace(std::move(__t._M_get()));
>>>> +           emplace(std::move(__t).operator*());
>>>>         }
>>>>
>>>>        template<typename _Up,
>>>> @@ -995,7 +1004,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>>>>         noexcept(is_nothrow_constructible_v<_Tp, _Up>)
>>>>         {
>>>>           if (__t)
>>>> -           emplace(std::move(__t._M_get()));
>>>> +           emplace(std::move(__t).operator*());
>>>>         }
>>>>
>>>>        template<typename... _Args,
>>>> @@ -1074,9 +1083,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>>>>           if (__u)
>>>>             {
>>>>               if (this->_M_is_engaged())
>>>> -               this->_M_get() = __u._M_get();
>>>> +               this->_M_get() = __u.operator*();
>>>>               else
>>>> -               this->_M_construct(__u._M_get());
>>>> +               this->_M_construct(__u.operator*());
>>>>             }
>>>>           else
>>>>             {
>>>> @@ -1108,9 +1117,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>>>>           if (__u)
>>>>             {
>>>>               if (this->_M_is_engaged())
>>>> -               this->_M_get() = std::move(__u._M_get());
>>>> +               this->_M_get() = std::move(__u).operator*();
>>>>               else
>>>> -               this->_M_construct(std::move(__u._M_get()));
>>>> +               this->_M_construct(std::move(__u).operator*());
>>>>             }
>>>>           else
>>>>             {
>>>> @@ -1310,7 +1319,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>>>>         and_then(_Fn&& __f) &
>>>>         {
>>>>           using _Up = remove_cvref_t<invoke_result_t<_Fn, _Tp&>>;
>>>> -         static_assert(__is_optional_v<remove_cvref_t<_Up>>,
>>>> +         static_assert(__is_optional_v<_Up>,
>>>>                         "the function passed to
>>>> std::optional<T>::and_then "
>>>>                         "must return a std::optional");
>>>>           if (has_value())
>>>> @@ -1338,7 +1347,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>>>>         and_then(_Fn&& __f) &&
>>>>         {
>>>>           using _Up = remove_cvref_t<invoke_result_t<_Fn, _Tp>>;
>>>> -         static_assert(__is_optional_v<remove_cvref_t<_Up>>,
>>>> +         static_assert(__is_optional_v<_Up>,
>>>>                         "the function passed to
>>>> std::optional<T>::and_then "
>>>>                         "must return a std::optional");
>>>>           if (has_value())
>>>> @@ -1352,7 +1361,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>>>>         and_then(_Fn&& __f) const &&
>>>>         {
>>>>           using _Up = remove_cvref_t<invoke_result_t<_Fn, const _Tp>>;
>>>> -         static_assert(__is_optional_v<remove_cvref_t<_Up>>,
>>>> +         static_assert(__is_optional_v<_Up>,
>>>>                         "the function passed to
>>>> std::optional<T>::and_then "
>>>>                         "must return a std::optional");
>>>>           if (has_value())
>>>> @@ -1453,6 +1462,305 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>>>>  #endif
>>>>      };
>>>>
>>>> +#if __cpp_lib_optional >= 202506L // C++26
>>>> +  template<typename _Tp>
>>>> +    class optional<_Tp&>
>>>> +    {
>>>> +      static_assert(__is_valid_contained_type_for_optional<_Tp&>);
>>>> +
>>>> +    public:
>>>> +      using value_type = _Tp;
>>>> +      using iterator = __gnu_cxx::__normal_iterator<_Tp*, optional>;
>>>> +
>>>> +      // 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.operator*());
>>>> +       }
>>>> +
>>>> +      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.operator*());
>>>> +       }
>>>> +
>>>> +      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).operator*());
>>>> +       }
>>>> +
>>>> +      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).operator*());
>>>> +       }
>>>> +
>>>> +      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); }
>>>> +
>>>> +      // Iterator support.
>>>> +      constexpr iterator begin() const noexcept
>>>> +      {
>>>> +       return iterator(_M_val);
>>>> +      }
>>>> +
>>>> +      constexpr iterator end() const noexcept
>>>> +      {
>>>> +       return begin() + has_value();
>>>> +      }
>>>> +
>>>> +      // 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
>>>> +      {
>>>> +        if (_M_val)
>>>> +          return *_M_val;
>>>> +        __throw_bad_optional_access();
>>>> +      }
>>>> +
>>>> +      // _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_constructible_v<_Xp, _Tp&>);
>>>> +         static_assert(is_convertible_v<_Up, _Xp>);
>>>> +         return _M_val ? *_M_val :
>>>> static_cast<_Xp>(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
>>>> +      {
>>>> +       _M_val = nullptr;
>>>> +      }
>>>> +
>>>> +    private:
>>>> +      _Tp *_M_val = nullptr;
>>>> +
>>>> +      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>
>>>>      using __optional_relop_t =
>>>>        enable_if_t<is_convertible_v<_Tp, bool>, bool>;
>>>> @@ -1740,19 +2048,32 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>>>>      noexcept(noexcept(__lhs.swap(__rhs)))
>>>>      { __lhs.swap(__rhs); }
>>>>
>>>> +#if __cpp_lib_optional >= 202506L
>>>> +  // We deviate from standard, that do not declared separate swap
>>>> overload
>>>> +  // from optional<T&>.
>>>> +  template<typename _Tp>
>>>> +    constexpr void
>>>> +    swap(optional<_Tp&>& __lhs, optional<_Tp&>& __rhs) noexcept
>>>> +    { __lhs.swap(__rhs); }
>>>> +#endif
>>>> +
>>>>    // _GLIBCXX_RESOLVE_LIB_DEFECTS
>>>>    // 2766. Swapping non-swappable types
>>>>    template<typename _Tp>
>>>>      enable_if_t<!(is_move_constructible_v<_Tp> && is_swappable_v<_Tp>)>
>>>>      swap(optional<_Tp>&, optional<_Tp>&) = delete;
>>>>
>>>> +#if __cpp_lib_optional >= 202506L
>>>> +  template<int = 0, typename _Tp>
>>>> +#else
>>>>    template<typename _Tp>
>>>> +#endif
>>>>      constexpr
>>>>      enable_if_t<is_constructible_v<decay_t<_Tp>, _Tp>,
>>>>                 optional<decay_t<_Tp>>>
>>>>      make_optional(_Tp&& __t)
>>>>      noexcept(is_nothrow_constructible_v<optional<decay_t<_Tp>>, _Tp>)
>>>> -    { return optional<decay_t<_Tp>>{ std::forward<_Tp>(__t) }; }
>>>> +    { return optional<decay_t<_Tp>>( std::forward<_Tp>(__t) ); }
>>>>
>>>>    template<typename _Tp, typename... _Args>
>>>>      constexpr
>>>> @@ -1760,7 +2081,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>>>>                 optional<_Tp>>
>>>>      make_optional(_Args&&... __args)
>>>>      noexcept(is_nothrow_constructible_v<_Tp, _Args...>)
>>>> -    { return optional<_Tp>{ in_place, std::forward<_Args>(__args)...
>>>> }; }
>>>> +    { return optional<_Tp>( in_place, std::forward<_Args>(__args)...
>>>> ); }
>>>>
>>>>    template<typename _Tp, typename _Up, typename... _Args>
>>>>      constexpr
>>>> @@ -1768,7 +2089,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>>>>                 optional<_Tp>>
>>>>      make_optional(initializer_list<_Up> __il, _Args&&... __args)
>>>>      noexcept(is_nothrow_constructible_v<_Tp, initializer_list<_Up>&,
>>>> _Args...>)
>>>> -    { return optional<_Tp>{ in_place, __il,
>>>> std::forward<_Args>(__args)... }; }
>>>> +    { return optional<_Tp>( in_place, __il,
>>>> std::forward<_Args>(__args)... ); }
>>>>
>>>>    // Hash.
>>>>
>>>> @@ -1796,6 +2117,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>>>>
>>>>    template<typename _Tp>
>>>>      struct hash<optional<_Tp>>
>>>> +    // hash for optional<T&> is disabled because
>>>> is_hash_enabled_for<T&> is false
>>>>      : public
>>>> __conditional_t<__is_hash_enabled_for<remove_const_t<_Tp>>,
>>>>                              __optional_hash<_Tp>,
>>>>                              __hash_not_enabled<_Tp>>
>>>> diff --git a/libstdc++-v3/testsuite/20_util/optional/make_optional-2.cc
>>>> b/libstdc++-v3/testsuite/20_util/optional/make_optional-2.cc
>>>> index f383b519c89..0aa2ac5ed93 100644
>>>> --- a/libstdc++-v3/testsuite/20_util/optional/make_optional-2.cc
>>>> +++ b/libstdc++-v3/testsuite/20_util/optional/make_optional-2.cc
>>>> @@ -70,7 +70,9 @@ static_assert( can_make_optional2<int, int&>::value );
>>>>  static_assert( noexcept(std::make_optional(i)) );
>>>>  static_assert( ! can_make_optional2<void, void>::value );
>>>>  static_assert( can_make_optional2<Cont, Cont>::value );
>>>> +#if __cplusplus <= 202302
>>>>  static_assert( noexcept(std::make_optional<Cont>({})) );
>>>> +#endif
>>>>  static_assert( can_make_optional2<Cont, const Cont&>::value );
>>>>  static_assert( ! noexcept(std::make_optional(c)) );
>>>>  static_assert( can_make_optional2<Cont, int>::value );
>>>> diff --git
>>>> a/libstdc++-v3/testsuite/20_util/optional/make_optional_neg.cc
>>>> b/libstdc++-v3/testsuite/20_util/optional/make_optional_neg.cc
>>>> new file mode 100644
>>>> index 00000000000..09499477233
>>>> --- /dev/null
>>>> +++ b/libstdc++-v3/testsuite/20_util/optional/make_optional_neg.cc
>>>> @@ -0,0 +1,20 @@
>>>> +// { dg-do compile { target c++17 }  }
>>>> +
>>>> +#include <initializer_list>
>>>> +#include <optional>
>>>> +
>>>> +struct S { int x; int* p; };
>>>> +int v;
>>>> +
>>>> +auto os1 = std::make_optional<S>({1, &v}); // { dg-error "no matching
>>>> function for" "" { target c++26 } }
>>>> +
>>>> +struct Cont
>>>> +{
>>>> +  Cont();
>>>> +  Cont(std::initializer_list<int>, int);
>>>> +};
>>>> +
>>>> +auto oc1 = std::make_optional<Cont>({}); // { dg-error "no matching
>>>> function for" "" { target c++26 } }
>>>> +
>>>> +// { dg-prune-output "no type named 'type' in 'struct std::enable_if" }
>>>> +// { dg-prune-output "type/value mismatch at argument 1 in template
>>>> parameter list" }
>>>> diff --git a/libstdc++-v3/testsuite/20_util/optional/monadic/ref_neg.cc
>>>> b/libstdc++-v3/testsuite/20_util/optional/monadic/ref_neg.cc
>>>> new file mode 100644
>>>> index 00000000000..ed1b42b1992
>>>> --- /dev/null
>>>> +++ b/libstdc++-v3/testsuite/20_util/optional/monadic/ref_neg.cc
>>>> @@ -0,0 +1,20 @@
>>>> +// { dg-do compile { target c++23 } }
>>>> +
>>>> +#include <optional>
>>>> +
>>>> +struct S { int x; int y; };
>>>> +
>>>> +void test()
>>>> +{
>>>> +  std::optional<S> o;
>>>> +  const std::optional<S>& co = o;
>>>> +
>>>> +  o.transform(&S::x);  // { dg-error "from here" "optional<int&>" {
>>>> target c++23_down } }
>>>> +  co.transform(&S::x); // { dg-error "from here" "optional<const
>>>> int&>" { target c++23_down } }
>>>> +  std::move(o).transform(&S::x);  // { dg-error "from here"
>>>> "optional<int&&>" }
>>>> +  std::move(co).transform(&S::x); // { dg-error "from here"
>>>> "optional<const int&&>" }
>>>> +}
>>>> +
>>>> +// { dg-prune-output "in a union may not have reference type" }
>>>> +// { dg-prune-output "static assertion failed" }
>>>> +// { dg-prune-output "forming pointer to reference type" }
>>>> diff --git a/libstdc++-v3/testsuite/20_util/optional/ref/access.cc
>>>> b/libstdc++-v3/testsuite/20_util/optional/ref/access.cc
>>>> new file mode 100644
>>>> index 00000000000..37c8ff355a6
>>>> --- /dev/null
>>>> +++ b/libstdc++-v3/testsuite/20_util/optional/ref/access.cc
>>>> @@ -0,0 +1,119 @@
>>>> +// { dg-do run { target c++26 }  }
>>>> +
>>>> +#include <optional>
>>>> +#include <type_traits>
>>>> +#include <testsuite_hooks.h>
>>>> +
>>>> +struct NonMovable
>>>> +{
>>>> +  constexpr NonMovable() {}
>>>> +  NonMovable(NonMovable&&) = delete;
>>>> +};
>>>> +
>>>> +template<typename T>
>>>> +constexpr
>>>> +void test_value(T& t)
>>>> +{
>>>> +  std::optional<T&> o1(t);
>>>> +  const std::optional<T&> co1(t);
>>>> +
>>>> +  static_assert( std::is_same_v<decltype(o1.value()), T&> );
>>>> +  VERIFY( &o1.value() == &t );
>>>> +
>>>> +  static_assert( std::is_same_v<decltype(co1.value()), T&> );
>>>> +  VERIFY( &co1.value() == &t );
>>>> +
>>>> +  static_assert( std::is_same_v<decltype(std::move(o1).value()), T&> );
>>>> +  VERIFY( &std::move(o1).value() == &t );
>>>> +
>>>> +  static_assert( std::is_same_v<decltype(std::move(co1).value()), T&>
>>>> );
>>>> +  VERIFY( &std::move(co1).value() == &t );
>>>> +
>>>> +  std::optional<const T&> o2(t);
>>>> +  static_assert( std::is_same_v<decltype(o2.value()), const T&> );
>>>> +  VERIFY( &o2.value() == &t );
>>>> +}
>>>> +
>>>> +struct Tracker
>>>> +{
>>>> +  int copy = 0;
>>>> +  int move = 0;
>>>> +
>>>> +  constexpr Tracker(int v) : copy(v), move(v) {}
>>>> +
>>>> +  constexpr Tracker(Tracker const& o)
>>>> +  : copy(o.copy+1), move(o.move)
>>>> +  {}
>>>> +
>>>> +  constexpr Tracker(Tracker&& o)
>>>> +  : copy(o.copy), move(o.move+1)
>>>> +  {}
>>>> +
>>>> +  Tracker& operator=(Tracker) = delete;
>>>> +};
>>>> +
>>>> +constexpr
>>>> +void test_value_or()
>>>> +{
>>>> +  Tracker t(100), u(200);
>>>> +  std::optional<Tracker&> o(t);
>>>> +
>>>> +  Tracker r1 = o.value_or(u);
>>>> +  VERIFY( r1.copy == 101 );
>>>> +  VERIFY( r1.move == 100 );
>>>> +  Tracker r2 = o.value_or(std::move(u));
>>>> +  VERIFY( r2.copy == 101 );
>>>> +  VERIFY( r2.move == 100 );
>>>> +  Tracker r3 = std::move(o).value_or(u);
>>>> +  VERIFY( r3.copy == 101 );
>>>> +  VERIFY( r3.move == 100 );
>>>> +  Tracker r4 = std::move(o).value_or(std::move(u));
>>>> +  VERIFY( r4.copy == 101 );
>>>> +  VERIFY( r4.move == 100 );
>>>> +
>>>> +  o.reset();
>>>> +  Tracker r5 = o.value_or(u);
>>>> +  VERIFY( r5.copy == 201 );
>>>> +  VERIFY( r5.move == 200 );
>>>> +  Tracker r6 = o.value_or(std::move(u));
>>>> +  VERIFY( r6.copy == 200 );
>>>> +  VERIFY( r6.move == 201 );
>>>> +  Tracker r7 = std::move(o).value_or(u);
>>>> +  VERIFY( r7.copy == 201 );
>>>> +  VERIFY( r7.move == 200 );
>>>> +  Tracker r8 = std::move(o).value_or(std::move(u));
>>>> +  VERIFY( r8.copy == 200 );
>>>> +  VERIFY( r8.move == 201 );
>>>> +}
>>>> +
>>>> +template<typename T>
>>>> +concept has_value_or_for = requires(std::optional<T&> t, T& u)
>>>> +{ t.value_or(u); };
>>>> +
>>>> +static_assert(  has_value_or_for<int> );
>>>> +static_assert(  has_value_or_for<NonMovable> );
>>>> +static_assert( !has_value_or_for<int[2]> );
>>>> +static_assert(  has_value_or_for<int(*)[2]> );
>>>> +static_assert( !has_value_or_for<int()> );
>>>> +static_assert(  has_value_or_for<int(*)()> );
>>>> +
>>>> +int i;
>>>> +NonMovable nm;
>>>> +int arr[2];
>>>> +int foo();
>>>> +
>>>> +int main()
>>>> +{
>>>> +  auto test_all = [] {
>>>> +    test_value<int>(i);
>>>> +    test_value<NonMovable>(nm);
>>>> +    test_value<int[2]>(arr);
>>>> +    test_value<int()>(foo);
>>>> +
>>>> +    test_value_or();
>>>> +    return true;
>>>> +  };
>>>> +
>>>> +  test_all();
>>>> +  static_assert(test_all());
>>>> +}
>>>> diff --git a/libstdc++-v3/testsuite/20_util/optional/ref/assign.cc
>>>> b/libstdc++-v3/testsuite/20_util/optional/ref/assign.cc
>>>> new file mode 100644
>>>> index 00000000000..be8b1c84eca
>>>> --- /dev/null
>>>> +++ b/libstdc++-v3/testsuite/20_util/optional/ref/assign.cc
>>>> @@ -0,0 +1,430 @@
>>>> +// { dg-do run { target c++26 }  }
>>>> +
>>>> +#include <optional>
>>>> +#include <type_traits>
>>>> +#include <testsuite_hooks.h>
>>>> +
>>>> +struct NonTrivial
>>>> +{
>>>> +  constexpr NonTrivial() {}
>>>> +  constexpr NonTrivial(NonTrivial const&) {};
>>>> +  constexpr ~NonTrivial() {};
>>>> +};
>>>> +
>>>> +struct NonMovable
>>>> +{
>>>> +  NonMovable() = default;
>>>> +  NonMovable(NonMovable&&) = delete;
>>>> +};
>>>> +
>>>> +template<typename T>
>>>> +struct Conv
>>>> +{
>>>> +  T t;
>>>> +
>>>> +  constexpr operator T() const noexcept
>>>> +  { return t; }
>>>> +};
>>>> +
>>>> +struct Tracker
>>>> +{
>>>> +  struct Counter
>>>> +  {
>>>> +    int copy;
>>>> +    int move;
>>>> +  };
>>>> +
>>>> +  Counter ctor{0,0};
>>>> +  Counter assign{0,0};
>>>> +
>>>> +  Tracker() = default;
>>>> +
>>>> +  constexpr Tracker(Tracker const& o)
>>>> +  : ctor(o.ctor), assign(o.assign)
>>>> +  {
>>>> +    ctor.copy += 1;
>>>> +  }
>>>> +
>>>> +  constexpr Tracker(Tracker&& o)
>>>> +  : ctor(o.ctor), assign(o.assign)
>>>> +  {
>>>> +    ctor.move += 1;
>>>> +  }
>>>> +
>>>> +  constexpr Tracker& operator=(const Tracker& o)
>>>> +  {
>>>> +    assign.copy += 1;
>>>> +    return *this;
>>>> +  }
>>>> +
>>>> +  constexpr Tracker& operator=(Tracker&& o)
>>>> +  {
>>>> +    assign.move += 1;
>>>> +    return *this;
>>>> +  }
>>>> +
>>>> +};
>>>> +
>>>> +template<typename T>
>>>> +void
>>>> +test_trivial()
>>>> +{
>>>> +  static_assert(std::is_copy_assignable_v<std::optional<T&>>);
>>>> +  static_assert(std::is_move_assignable_v<std::optional<T&>>);
>>>> +}
>>>> +
>>>> +constexpr void
>>>> +test_trivial_all()
>>>> +{
>>>> +  test_trivial<int>();
>>>> +  test_trivial<NonTrivial>();
>>>> +  test_trivial<std::optional<int&>>();
>>>> +}
>>>> +
>>>> +constexpr void
>>>> +test_copy()
>>>> +{
>>>> +  Tracker t, u;
>>>> +  std::optional<Tracker&> e;
>>>> +  std::optional<Tracker&> o1(t);
>>>> +  std::optional<Tracker&> o2(u);
>>>> +
>>>> +  o2 = o1;
>>>> +  VERIFY( o1.has_value() );
>>>> +  VERIFY( &o1.value() == &t );
>>>> +  VERIFY( o2.has_value() );
>>>> +  VERIFY( &o2.value() == &t );
>>>> +  VERIFY( t.ctor.copy == 0 );
>>>> +  VERIFY( t.ctor.move == 0 );
>>>> +  VERIFY( t.assign.copy == 0 );
>>>> +  VERIFY( t.assign.move == 0 );
>>>> +
>>>> +  o2 = e;
>>>> +  VERIFY( !o2.has_value() );
>>>> +
>>>> +  o2 = std::move(o1);
>>>> +  VERIFY( o1.has_value() );
>>>> +  VERIFY( &o1.value() == &t );
>>>> +  VERIFY( o2.has_value() );
>>>> +  VERIFY( &o2.value() == &t );
>>>> +  VERIFY( t.ctor.copy == 0 );
>>>> +  VERIFY( t.ctor.move == 0 );
>>>> +  VERIFY( t.assign.copy == 0 );
>>>> +  VERIFY( t.assign.move == 0 );
>>>> +
>>>> +  o2 = std::move(e);
>>>> +  VERIFY( !o2.has_value() );
>>>> +}
>>>> +
>>>> +template<typename T, typename U>
>>>> +concept can_emplace = requires (T t, U&& u)
>>>> +{ t.emplace(std::forward<U>(u)); };
>>>> +
>>>> +constexpr void
>>>> +test_from_value()
>>>> +{
>>>> +  NonTrivial v, u;
>>>> +  const NonTrivial& cv = v;
>>>> +  const std::optional<NonTrivial&> s(u);
>>>> +  std::optional<NonTrivial&> o1;
>>>> +  std::optional<const NonTrivial&> co1;
>>>> +
>>>> +  o1 = s;
>>>> +  o1 = v;
>>>> +  VERIFY( o1.has_value() );
>>>> +  VERIFY( &o1.value() == &v );
>>>> +
>>>> +  o1.reset();
>>>> +  VERIFY( !o1.has_value() );
>>>> +
>>>> +  o1 = v;
>>>> +  VERIFY( o1.has_value() );
>>>> +  VERIFY( &o1.value() == &v );
>>>> +  static_assert( !std::is_assignable_v<std::optional<NonTrivial&>,
>>>> +                                      const NonTrivial&> );
>>>> +  static_assert( !std::is_assignable_v<std::optional<NonTrivial&>,
>>>> +                                      NonTrivial> );
>>>> +  static_assert( !std::is_assignable_v<std::optional<NonTrivial&>,
>>>> +                                      const NonTrivial> );
>>>> +
>>>> +  o1 = s;
>>>> +  o1.emplace(v);
>>>> +  VERIFY( o1.has_value() );
>>>> +  VERIFY( &o1.value() == &v );
>>>> +
>>>> +  o1 = std::nullopt;
>>>> +  VERIFY( !o1.has_value() );
>>>> +
>>>> +  o1.emplace(v);
>>>> +  VERIFY( o1.has_value() );
>>>> +  VERIFY( &o1.value() == &v );
>>>> +
>>>> +  static_assert( !can_emplace<std::optional<NonTrivial&>, const
>>>> NonTrivial&> );
>>>> +  static_assert( !can_emplace<std::optional<NonTrivial&>, NonTrivial>
>>>> );
>>>> +  static_assert( !can_emplace<std::optional<NonTrivial&>, const
>>>> NonTrivial> );
>>>> +
>>>> +  co1 = s;
>>>> +  co1 = v;
>>>> +  VERIFY( co1.has_value() );
>>>> +  VERIFY( &co1.value() == &v );
>>>> +
>>>> +  co1 = std::nullopt;
>>>> +  co1 = cv;
>>>> +  VERIFY( co1.has_value() );
>>>> +  VERIFY( &co1.value() == &v );
>>>> +  // No binding to rvalue
>>>> +  static_assert( !std::is_assignable_v<std::optional<const
>>>> NonTrivial&>,
>>>> +                                      NonTrivial> );
>>>> +  static_assert( !std::is_assignable_v<std::optional<const
>>>> NonTrivial&>,
>>>> +                                      const NonTrivial> );
>>>> +
>>>> +  co1 = std::nullopt;
>>>> +  co1.emplace(v);
>>>> +  VERIFY( co1.has_value() );
>>>> +  VERIFY( &co1.value() == &v );
>>>> +
>>>> +  co1 = s;
>>>> +  co1.emplace(cv);
>>>> +  VERIFY( co1.has_value() );
>>>> +  VERIFY( &co1.value() == &v );
>>>> +  // No binding to rvalue
>>>> +  static_assert( !can_emplace<std::optional<const NonTrivial&>, const
>>>> NonTrivial> );
>>>> +  static_assert( !can_emplace<std::optional<const NonTrivial&>,
>>>> NonTrivial> );
>>>> +
>>>> +
>>>> +  // Conversion create a pr-value that would bind to temporary
>>>> +  static_assert( !std::is_assignable_v<std::optional<NonTrivial&>,
>>>> +                                      Conv<NonTrivial>&> );
>>>> +  static_assert( !std::is_assignable_v<std::optional<NonTrivial&>,
>>>> +                                      const Conv<NonTrivial>&> );
>>>> +  static_assert( !std::is_assignable_v<std::optional<NonTrivial&>,
>>>> +                                      Conv<NonTrivial>> );
>>>> +  static_assert( !std::is_assignable_v<std::optional<NonTrivial&>,
>>>> +                                      const Conv<NonTrivial>> );
>>>> +
>>>> +  static_assert( !can_emplace<std::optional<NonTrivial&>,
>>>> Conv<NonTrivial>&> );
>>>> +  static_assert( !can_emplace<std::optional<NonTrivial&>, const
>>>> Conv<NonTrivial>&> );
>>>> +  static_assert( !can_emplace<std::optional<NonTrivial&>,
>>>> Conv<NonTrivial>> );
>>>> +  static_assert( !can_emplace<std::optional<NonTrivial&>, const
>>>> Conv<NonTrivial>> );
>>>> +
>>>> +  Conv<NonTrivial&> rw(v);
>>>> +  const Conv<NonTrivial&> crw(v);
>>>> +
>>>> +  o1 = std::nullopt;
>>>> +  o1 = rw;
>>>> +  VERIFY( o1.has_value() );
>>>> +  VERIFY( &o1.value() == &v );
>>>> +  o1 = s;
>>>> +  o1 = crw;
>>>> +  VERIFY( o1.has_value() );
>>>> +  VERIFY( &o1.value() == &v );
>>>> +  o1 = s;
>>>> +  o1 = std::move(rw);
>>>> +  VERIFY( o1.has_value() );
>>>> +  VERIFY( &o1.value() == &v );
>>>> +  o1 = std::nullopt;
>>>> +  o1 = std::move(crw);
>>>> +  VERIFY( o1.has_value() );
>>>> +  VERIFY( &o1.value() == &v );
>>>> +
>>>> +  o1 = s;
>>>> +  o1.emplace(rw);
>>>> +  VERIFY( o1.has_value() );
>>>> +  VERIFY( &o1.value() == &v );
>>>> +  o1 = std::nullopt;
>>>> +  o1.emplace(crw);
>>>> +  VERIFY( o1.has_value() );
>>>> +  VERIFY( &o1.value() == &v );
>>>> +  o1 = std::nullopt;
>>>> +  o1.emplace(std::move(rw));
>>>> +  VERIFY( o1.has_value() );
>>>> +  VERIFY( &o1.value() == &v );
>>>> +  o1 = s;
>>>> +  o1.emplace(std::move(crw));
>>>> +  VERIFY( o1.has_value() );
>>>> +  VERIFY( &o1.value() == &v );
>>>> +}
>>>> +
>>>> +constexpr void
>>>> +test_from_opt_value()
>>>> +{
>>>> +  NonTrivial u;
>>>> +  std::optional<NonTrivial> v(std::in_place);
>>>> +  const std::optional<NonTrivial>& cv = v;
>>>> +
>>>> +  const std::optional<NonTrivial&> s(u);
>>>> +  std::optional<NonTrivial&> o1;
>>>> +  std::optional<const NonTrivial&> co1;
>>>> +
>>>> +  o1 = s;
>>>> +  o1 = v;
>>>> +  VERIFY( o1.has_value() );
>>>> +  VERIFY( &o1.value() == &v.value() );
>>>> +  o1 = std::nullopt;
>>>> +  o1 = v;
>>>> +  VERIFY( o1.has_value() );
>>>> +  VERIFY( &o1.value() == &v.value() );
>>>> +  static_assert( !std::is_assignable_v<std::optional<NonTrivial&>,
>>>> +                                      const
>>>> std::optional<NonTrivial>&> );
>>>> +  static_assert( !std::is_assignable_v<std::optional<NonTrivial&>,
>>>> +                                      std::optional<NonTrivial>> );
>>>> +  static_assert( !std::is_assignable_v<std::optional<NonTrivial&>,
>>>> +                                      const std::optional<NonTrivial>>
>>>> );
>>>> +
>>>> +  co1 = s;
>>>> +  co1 = v;
>>>> +  VERIFY( co1.has_value() );
>>>> +  VERIFY( &co1.value() == &v.value() );
>>>> +  co1 = std::nullopt;
>>>> +  co1 = cv;
>>>> +  VERIFY( co1.has_value() );
>>>> +  VERIFY( &co1.value() == &v.value() );
>>>> +  // No binding to rvalue
>>>> +  static_assert( !std::is_assignable_v<std::optional<const
>>>> NonTrivial&>,
>>>> +                                      std::optional<NonTrivial>> );
>>>> +  static_assert( !std::is_assignable_v<std::optional<const
>>>> NonTrivial&>,
>>>> +                                      const std::optional<NonTrivial>>
>>>> );
>>>> +
>>>> +  // Conversion create a pr-value that would bind to temporary
>>>> +  static_assert( !std::is_assignable_v<std::optional<NonTrivial&>,
>>>> +
>>>> std::optional<Conv<NonTrivial>>&> );
>>>> +  static_assert( !std::is_assignable_v<std::optional<NonTrivial&>,
>>>> +                                      const
>>>> std::optional<Conv<NonTrivial>>&> );
>>>> +  static_assert( !std::is_assignable_v<std::optional<NonTrivial&>,
>>>> +                                      std::optional<Conv<NonTrivial>>>
>>>> );
>>>> +  static_assert( !std::is_assignable_v<std::optional<NonTrivial&>,
>>>> +                                      const
>>>> std::optional<Conv<NonTrivial>>> );
>>>> +
>>>> +  std::optional<Conv<NonTrivial&>> rw(*v);
>>>> +  std::optional<const Conv<NonTrivial&>> crw(*v);
>>>> +
>>>> +  o1 = std::nullopt;
>>>> +  o1 = rw;
>>>> +  VERIFY( o1.has_value() );
>>>> +  VERIFY( &o1.value() == &v.value() );
>>>> +  o1 = s;
>>>> +  o1 = crw;
>>>> +  VERIFY( o1.has_value() );
>>>> +  VERIFY( &o1.value() == &v.value() );
>>>> +  o1 = s;
>>>> +  o1 = std::move(rw);
>>>> +  VERIFY( o1.has_value() );
>>>> +  VERIFY( &o1.value() == &v.value() );
>>>> +  o1 = std::nullopt;
>>>> +  o1 = std::move(crw);
>>>> +  VERIFY( o1.has_value() );
>>>> +  VERIFY( &o1.value() == &v.value() );
>>>> +}
>>>> +
>>>> +constexpr void
>>>> +test_to_opt_value()
>>>> +{
>>>> +  Tracker t;
>>>> +  std::optional<Tracker&> er;
>>>> +  std::optional<Tracker&> r(t);
>>>> +  const std::optional<Tracker&> cr(t);
>>>> +
>>>> +  std::optional<Tracker> o1;
>>>> +  o1 = r;
>>>> +  VERIFY( o1.has_value() );
>>>> +  VERIFY( o1->ctor.copy == 1 );
>>>> +  VERIFY( o1->ctor.move == 0 );
>>>> +  VERIFY( o1->assign.copy == 0 );
>>>> +  VERIFY( o1->assign.move == 0 );
>>>> +
>>>> +  o1 = r;
>>>> +  VERIFY( o1.has_value() );
>>>> +  VERIFY( o1->ctor.copy == 1 );
>>>> +  VERIFY( o1->ctor.move == 0 );
>>>> +  VERIFY( o1->assign.copy == 1 );
>>>> +  VERIFY( o1->assign.move == 0 );
>>>> +
>>>> +  o1 = er;
>>>> +  VERIFY( !o1.has_value() );
>>>> +
>>>> +  o1 = cr;
>>>> +  VERIFY( o1.has_value() );
>>>> +  VERIFY( o1->ctor.copy == 1 );
>>>> +  VERIFY( o1->ctor.move == 0 );
>>>> +  VERIFY( o1->assign.copy == 0 );
>>>> +  VERIFY( o1->assign.move == 0 );
>>>> +
>>>> +  o1 = cr;
>>>> +  VERIFY( o1.has_value() );
>>>> +  VERIFY( o1->ctor.copy == 1 );
>>>> +  VERIFY( o1->ctor.move == 0 );
>>>> +  VERIFY( o1->assign.copy == 1 );
>>>> +  VERIFY( o1->assign.move == 0 );
>>>> +
>>>> +  o1 = std::move(er);
>>>> +
>>>> +  o1 = std::move(r);
>>>> +  VERIFY( o1.has_value() );
>>>> +  VERIFY( o1->ctor.copy == 1 );
>>>> +  VERIFY( o1->ctor.move == 0 );
>>>> +  VERIFY( o1->assign.copy == 0 );
>>>> +  VERIFY( o1->assign.move == 0 );
>>>> +
>>>> +  o1 = std::move(cr);
>>>> +  VERIFY( o1.has_value() );
>>>> +  VERIFY( o1->ctor.copy == 1 );
>>>> +  VERIFY( o1->ctor.move == 0 );
>>>> +  VERIFY( o1->assign.copy == 1 );
>>>> +  VERIFY( o1->assign.move == 0 );
>>>> +}
>>>> +
>>>> +constexpr void
>>>> +test_swap()
>>>> +{
>>>> +  NonMovable a, b;
>>>> +  std::optional<NonMovable&> oa(a), ob(b);
>>>> +
>>>> +  oa.swap(ob);
>>>> +  static_assert(noexcept(oa.swap(ob)));
>>>> +  VERIFY( oa.has_value() );
>>>> +  VERIFY( &oa.value() == &b );
>>>> +  VERIFY( ob.has_value() );
>>>> +  VERIFY( &ob.value() == &a );
>>>> +
>>>> +  swap(oa, ob);
>>>> +
>>>> static_assert(std::is_nothrow_swappable_v<std::optional<NonMovable&>>);
>>>> +  VERIFY( oa.has_value() );
>>>> +  VERIFY( &oa.value() == &a );
>>>> +  VERIFY( ob.has_value() );
>>>> +  VERIFY( &ob.value() == &b );
>>>> +
>>>> +  ob.reset();
>>>> +  oa.swap(ob);
>>>> +  VERIFY( !oa.has_value() );
>>>> +  VERIFY( ob.has_value() );
>>>> +  VERIFY( &ob.value() == &a );
>>>> +
>>>> +  ob.reset();
>>>> +  std::swap(oa, ob);
>>>> +  VERIFY( !oa.has_value() );
>>>> +  VERIFY( !ob.has_value() );
>>>> +
>>>> +  std::optional<const NonMovable&> ca(a), cb(b);
>>>> +  swap(ca, cb);
>>>> +  VERIFY( ca.has_value() );
>>>> +  VERIFY( &ca.value() == &b );
>>>> +  VERIFY( cb.has_value() );
>>>> +  VERIFY( &cb.value() == &a );
>>>> +
>>>> +  static_assert(!std::is_swappable_with_v<std::optional<int>&,
>>>> std::optional<int&>&>);
>>>> +}
>>>> +
>>>> +int main()
>>>> +{
>>>> +  auto test_all = [] {
>>>> +    test_copy();
>>>> +    test_from_value();
>>>> +    test_from_opt_value();
>>>> +    test_to_opt_value();
>>>> +    test_swap();
>>>> +    return true;
>>>> +  };
>>>> +
>>>> +  test_all();
>>>> +  static_assert(test_all());
>>>> +}
>>>> diff --git a/libstdc++-v3/testsuite/20_util/optional/ref/cons.cc
>>>> b/libstdc++-v3/testsuite/20_util/optional/ref/cons.cc
>>>> new file mode 100644
>>>> index 00000000000..b13e8b92329
>>>> --- /dev/null
>>>> +++ b/libstdc++-v3/testsuite/20_util/optional/ref/cons.cc
>>>> @@ -0,0 +1,356 @@
>>>> +// { dg-do run { target c++26 }  }
>>>> +
>>>> +#include <optional>
>>>> +#include <type_traits>
>>>> +#include <testsuite_hooks.h>
>>>> +
>>>> +struct NonTrivial
>>>> +{
>>>> +  constexpr NonTrivial() {}
>>>> +  constexpr NonTrivial(NonTrivial const&) {};
>>>> +  constexpr ~NonTrivial() {};
>>>> +};
>>>> +
>>>> +struct NonMovable
>>>> +{
>>>> +  constexpr NonMovable() {}
>>>> +  NonMovable(NonMovable&&) = delete;
>>>> +};
>>>> +
>>>> +template<typename T>
>>>> +struct Conv
>>>> +{
>>>> +  T t;
>>>> +
>>>> +  constexpr operator T() const noexcept
>>>> +  { return t; }
>>>> +};
>>>> +
>>>> +struct Tracker
>>>> +{
>>>> +  int copy = 0;
>>>> +  int move = 0;
>>>> +
>>>> +  Tracker() = default;
>>>> +
>>>> +  constexpr Tracker(Tracker const& o)
>>>> +  : copy(o.copy+1), move(o.move)
>>>> +  {}
>>>> +
>>>> +  constexpr Tracker(Tracker&& o)
>>>> +  : copy(o.copy), move(o.move+1)
>>>> +  {}
>>>> +
>>>> +  Tracker& operator=(Tracker) = delete;
>>>> +};
>>>> +
>>>> +template<typename T>
>>>> +void
>>>> +test_trivial()
>>>> +{
>>>> +  static_assert(std::is_trivially_copyable_v<std::optional<T&>>);
>>>> +  static_assert(std::is_copy_constructible_v<std::optional<T&>>);
>>>> +  static_assert(std::is_move_constructible_v<std::optional<T&>>);
>>>> +  static_assert(std::is_destructible_v<std::optional<T&>>);
>>>> +}
>>>> +
>>>> +constexpr void
>>>> +test_trivial_all()
>>>> +{
>>>> +  test_trivial<int>();
>>>> +  test_trivial<NonTrivial>();
>>>> +  test_trivial<NonMovable>();
>>>> +  test_trivial<std::optional<int&>>();
>>>> +}
>>>> +
>>>> +constexpr void
>>>> +test_copy()
>>>> +{
>>>> +  Tracker t;
>>>> +  std::optional<Tracker&> o1(t);
>>>> +  VERIFY( o1.has_value() );
>>>> +  VERIFY( &o1.value() == &t );
>>>> +  VERIFY( t.copy == 0 );
>>>> +  VERIFY( t.move == 0 );
>>>> +
>>>> +  std::optional<Tracker&> o2(o1);
>>>> +  VERIFY( o1.has_value() );
>>>> +  VERIFY( &o1.value() == &t );
>>>> +  VERIFY( o2.has_value() );
>>>> +  VERIFY( &o2.value() == &t );
>>>> +  VERIFY( t.copy == 0 );
>>>> +  VERIFY( t.move == 0 );
>>>> +
>>>> +  std::optional<Tracker&> o3(std::move(o1));
>>>> +  VERIFY( o1.has_value() );
>>>> +  VERIFY( &o1.value() == &t );
>>>> +  VERIFY( o3.has_value() );
>>>> +  VERIFY( &o3.value() == &t );
>>>> +  VERIFY( t.copy == 0 );
>>>> +  VERIFY( t.move == 0 );
>>>> +
>>>> +  std::optional<Tracker&> e;
>>>> +  VERIFY( !e.has_value() );
>>>> +
>>>> +  std::optional<Tracker&> o4(e);
>>>> +  VERIFY( !e.has_value() );
>>>> +  VERIFY( !o4.has_value() );
>>>> +
>>>> +  std::optional<Tracker&> o5(std::move(e));
>>>> +  VERIFY( !e.has_value() );
>>>> +  VERIFY( !o5.has_value() );
>>>> +}
>>>> +
>>>> +
>>>> +constexpr void
>>>> +test_from_value()
>>>> +{
>>>> +  NonTrivial v;
>>>> +  const NonTrivial& cv = v;
>>>> +
>>>> +  std::optional<NonTrivial&> o1(v);
>>>> +  VERIFY( o1.has_value() );
>>>> +  VERIFY( &o1.value() == &v );
>>>> +  static_assert( !std::is_constructible_v<std::optional<NonTrivial&>,
>>>> +                                         const NonTrivial&> );
>>>> +  static_assert( !std::is_constructible_v<std::optional<NonTrivial&>,
>>>> +                                         NonTrivial> );
>>>> +  static_assert( !std::is_constructible_v<std::optional<NonTrivial&>,
>>>> +                                         const NonTrivial> );
>>>> +
>>>> +  std::optional<NonTrivial&> o2(std::in_place, v);
>>>> +  VERIFY( o2.has_value() );
>>>> +  VERIFY( &o2.value() == &v );
>>>> +  static_assert( !std::is_constructible_v<std::optional<NonTrivial&>,
>>>> +                                         std::in_place_t, const
>>>> NonTrivial&> );
>>>> +  static_assert( !std::is_constructible_v<std::optional<NonTrivial&>,
>>>> +                                         std::in_place_t, NonTrivial>
>>>> );
>>>> +  static_assert( !std::is_constructible_v<std::optional<NonTrivial&>,
>>>> +                                         std::in_place_t, const
>>>> NonTrivial> );
>>>> +
>>>> +  std::optional<const NonTrivial&> co1(v);
>>>> +  VERIFY( co1.has_value() );
>>>> +  VERIFY( &co1.value() == &v );
>>>> +  std::optional<const NonTrivial&> co2(cv);
>>>> +  VERIFY( co2.has_value() );
>>>> +  VERIFY( &co2.value() == &v );
>>>> +  // No binding to rvalue
>>>> +  static_assert( !std::is_constructible_v<std::optional<const
>>>> NonTrivial&>,
>>>> +                                         NonTrivial> );
>>>> +  static_assert( !std::is_constructible_v<std::optional<const
>>>> NonTrivial&>,
>>>> +                                         const NonTrivial> );
>>>> +
>>>> +  std::optional<const NonTrivial&> co3(std::in_place, v);
>>>> +  VERIFY( co3.has_value() );
>>>> +  VERIFY( &co3.value() == &v );
>>>> +  std::optional<const NonTrivial&> co4(std::in_place, cv);
>>>> +  VERIFY( co4.has_value() );
>>>> +  VERIFY( &co4.value() == &v );
>>>> +  // No binding to rvalue
>>>> +  static_assert( !std::is_constructible_v<std::optional<const
>>>> NonTrivial&>,
>>>> +                                         std::in_place_t, NonTrivial>
>>>> );
>>>> +  static_assert( !std::is_constructible_v<std::optional<const
>>>> NonTrivial&>,
>>>> +                                         std::in_place_t, const
>>>> NonTrivial> );
>>>> +
>>>> +  // Conversion create a pr-value that would bind to temporary
>>>> +  static_assert( !std::is_constructible_v<std::optional<NonTrivial&>,
>>>> +                                         Conv<NonTrivial>&> );
>>>> +  static_assert( !std::is_constructible_v<std::optional<NonTrivial&>,
>>>> +                                         const Conv<NonTrivial>&> );
>>>> +  static_assert( !std::is_constructible_v<std::optional<NonTrivial&>,
>>>> +                                         Conv<NonTrivial>> );
>>>> +  static_assert( !std::is_constructible_v<std::optional<NonTrivial&>,
>>>> +                                         const Conv<NonTrivial>> );
>>>> +
>>>> +  static_assert( !std::is_constructible_v<std::optional<NonTrivial&>,
>>>> +                                         std::in_place_t,
>>>> Conv<NonTrivial>&> );
>>>> +  static_assert( !std::is_constructible_v<std::optional<NonTrivial&>,
>>>> +                                         std::in_place_t, const
>>>> Conv<NonTrivial>&> );
>>>> +  static_assert( !std::is_constructible_v<std::optional<NonTrivial&>,
>>>> +                                         std::in_place_t,
>>>> Conv<NonTrivial>> );
>>>> +  static_assert( !std::is_constructible_v<std::optional<NonTrivial&>,
>>>> +                                         std::in_place_t, const
>>>> Conv<NonTrivial>> );
>>>> +
>>>> +  Conv<NonTrivial&> rw(v);
>>>> +  const Conv<NonTrivial&> crw(v);
>>>> +
>>>> +  std::optional<NonTrivial&> ro1(rw);
>>>> +  VERIFY( ro1.has_value() );
>>>> +  VERIFY( &ro1.value() == &v );
>>>> +  std::optional<NonTrivial&> ro2(crw);
>>>> +  VERIFY( ro2.has_value() );
>>>> +  VERIFY( &ro2.value() == &v );
>>>> +  std::optional<NonTrivial&> ro3(std::move(rw));
>>>> +  VERIFY( ro3.has_value() );
>>>> +  VERIFY( &ro3.value() == &v );
>>>> +  std::optional<NonTrivial&> ro4(std::move(crw));
>>>> +  VERIFY( ro4.has_value() );
>>>> +  VERIFY( &ro4.value() == &v );
>>>> +
>>>> +  std::optional<NonTrivial&> ro5(std::in_place, rw);
>>>> +  VERIFY( ro5.has_value() );
>>>> +  VERIFY( &ro5.value() == &v );
>>>> +  std::optional<NonTrivial&> ro6(std::in_place, crw);
>>>> +  VERIFY( ro6.has_value() );
>>>> +  VERIFY( &ro6.value() == &v );
>>>> +  std::optional<NonTrivial&> ro7(std::in_place, std::move(rw));
>>>> +  VERIFY( ro7.has_value() );
>>>> +  VERIFY( &ro7.value() == &v );
>>>> +  std::optional<NonTrivial&> ro8(std::in_place, std::move(crw));
>>>> +  VERIFY( ro8.has_value() );
>>>> +  VERIFY( &ro8.value() == &v );
>>>> +}
>>>> +
>>>> +constexpr void
>>>> +test_from_opt_value()
>>>> +{
>>>> +  std::optional<NonTrivial> v(std::in_place);
>>>> +  const std::optional<NonTrivial>& cv = v;
>>>> +
>>>> +  std::optional<NonTrivial&> o1(v);
>>>> +  VERIFY( o1.has_value() );
>>>> +  VERIFY( &o1.value() == &v.value() );
>>>> +  static_assert( !std::is_constructible_v<std::optional<NonTrivial&>,
>>>> +                                         const
>>>> std::optional<NonTrivial>&> );
>>>> +  static_assert( !std::is_constructible_v<std::optional<NonTrivial&>,
>>>> +                                         std::optional<NonTrivial>> );
>>>> +  static_assert( !std::is_constructible_v<std::optional<NonTrivial&>,
>>>> +                                         const
>>>> std::optional<NonTrivial>> );
>>>> +
>>>> +  std::optional<const NonTrivial&> co1(v);
>>>> +  VERIFY( co1.has_value() );
>>>> +  VERIFY( &co1.value() == &v.value() );
>>>> +  std::optional<const NonTrivial&> co2(cv);
>>>> +  VERIFY( co2.has_value() );
>>>> +  VERIFY( &co2.value() == &v.value() );
>>>> +  // No binding to rvalue
>>>> +  static_assert( !std::is_constructible_v<std::optional<const
>>>> NonTrivial&>,
>>>> +                                         std::optional<NonTrivial>> );
>>>> +  static_assert( !std::is_constructible_v<std::optional<const
>>>> NonTrivial&>,
>>>> +                                         const
>>>> std::optional<NonTrivial>> );
>>>> +
>>>> +  // Conversion create a pr-value that would bind to temporary
>>>> +  static_assert( !std::is_constructible_v<std::optional<NonTrivial&>,
>>>> +
>>>>  std::optional<Conv<NonTrivial>>&> );
>>>> +  static_assert( !std::is_constructible_v<std::optional<NonTrivial&>,
>>>> +                                         const
>>>> std::optional<Conv<NonTrivial>>&> );
>>>> +  static_assert( !std::is_constructible_v<std::optional<NonTrivial&>,
>>>> +
>>>>  std::optional<Conv<NonTrivial>>> );
>>>> +  static_assert( !std::is_constructible_v<std::optional<NonTrivial&>,
>>>> +                                         const
>>>> std::optional<Conv<NonTrivial>>> );
>>>> +
>>>> +  std::optional<Conv<NonTrivial&>> rw(*v);
>>>> +  std::optional<const Conv<NonTrivial&>> crw(*v);
>>>> +
>>>> +  std::optional<NonTrivial&> ro1(rw);
>>>> +  VERIFY( ro1.has_value() );
>>>> +  VERIFY( &ro1.value() == &v.value() );
>>>> +  std::optional<NonTrivial&> ro2(crw);
>>>> +  VERIFY( ro2.has_value() );
>>>> +  VERIFY( &ro2.value() == &v.value() );
>>>> +  std::optional<NonTrivial&> ro3(std::move(rw));
>>>> +  VERIFY( ro3.has_value() );
>>>> +  VERIFY( &ro3.value() == &v.value() );
>>>> +  std::optional<NonTrivial&> ro4(std::move(crw));
>>>> +  VERIFY( ro4.has_value() );
>>>> +  VERIFY( &ro4.value() == &v.value() );
>>>> +}
>>>> +
>>>> +constexpr void
>>>> +test_to_opt_value()
>>>> +{
>>>> +  Tracker t;
>>>> +  std::optional<Tracker&> r(t);
>>>> +  const std::optional<Tracker&> cr(t);
>>>> +
>>>> +  std::optional<Tracker> o1(r);
>>>> +  VERIFY( o1.has_value() );
>>>> +  VERIFY( o1->copy == 1 );
>>>> +  VERIFY( o1->move == 0 );
>>>> +
>>>> +  std::optional<Tracker> o2(cr);
>>>> +  VERIFY( o2.has_value() );
>>>> +  VERIFY( o2->copy == 1 );
>>>> +  VERIFY( o2->move == 0 );
>>>> +
>>>> +  std::optional<Tracker> o3(std::move(r));
>>>> +  VERIFY( o3.has_value() );
>>>> +  VERIFY( o3->copy == 1 );
>>>> +  VERIFY( o3->move == 0 );
>>>> +
>>>> +  std::optional<Tracker> o4(std::move(cr));
>>>> +  VERIFY( o4.has_value() );
>>>> +  VERIFY( o4->copy == 1 );
>>>> +  VERIFY( o4->move == 0 );
>>>> +
>>>> +  std::optional<Tracker&> er;
>>>> +  const std::optional<Tracker&> cer;
>>>> +
>>>> +  std::optional<Tracker> e1(er);
>>>> +  VERIFY( !e1.has_value() );
>>>> +
>>>> +  std::optional<Tracker> e2(cer);
>>>> +  VERIFY( !e2.has_value() );
>>>> +
>>>> +  std::optional<Tracker> e3(std::move(er));
>>>> +  VERIFY( !e3.has_value() );
>>>> +
>>>> +  std::optional<Tracker> e4(std::move(cer));
>>>> +  VERIFY( !e4.has_value() );
>>>> +}
>>>> +
>>>> +constexpr void
>>>> +test_opt_opt()
>>>> +{
>>>> +  std::optional<int> s(43);
>>>> +
>>>> +  std::optional<std::optional<int>&> o1(s);
>>>> +  VERIFY( o1.has_value() );
>>>> +  VERIFY( &o1.value() == &s );
>>>> +
>>>> +  std::optional<std::optional<int>&> o2(std::in_place, s);
>>>> +  VERIFY( o2.has_value() );
>>>> +  VERIFY( &o2.value() == &s );
>>>> +
>>>> +  std::optional<std::optional<int>> o3(o1);
>>>> +  VERIFY( o2.has_value() );
>>>> +  VERIFY( o2.value().has_value() );
>>>> +  VERIFY( o2.value() == 43 );
>>>> +
>>>> +  s.reset();
>>>> +  std::optional<std::optional<int>&> o4(s);
>>>> +  VERIFY( o4.has_value() );
>>>> +  VERIFY( &o4.value() == &s );
>>>> +
>>>> +  std::optional<std::optional<int>&> o5(std::in_place, s);
>>>> +  VERIFY( o5.has_value() );
>>>> +  VERIFY( &o5.value() == &s );
>>>> +
>>>> +  std::optional<std::optional<int>> o6(o1);
>>>> +  VERIFY( o6.has_value() );
>>>> +  VERIFY( !o6.value().has_value() );
>>>> +
>>>> +  std::optional<std::optional<int>> s2(std::in_place);
>>>> +  std::optional<std::optional<int>&> oo1(s2);
>>>> +  VERIFY( oo1.has_value() );
>>>> +  VERIFY( &oo1.value() == &s2.value() );
>>>> +
>>>> +  s2.reset();
>>>> +  std::optional<std::optional<int>&> oo2(s2);
>>>> +  VERIFY( !oo2.has_value() );
>>>> +}
>>>> +
>>>> +int main()
>>>> +{
>>>> +  auto test_all = [] {
>>>> +    test_copy();
>>>> +    test_from_value();
>>>> +    test_from_opt_value();
>>>> +    test_to_opt_value();
>>>> +    test_opt_opt();
>>>> +    return true;
>>>> +  };
>>>> +
>>>> +  test_all();
>>>> +  static_assert(test_all());
>>>> +}
>>>> diff --git
>>>> a/libstdc++-v3/testsuite/20_util/optional/ref/internal_traits.cc
>>>> b/libstdc++-v3/testsuite/20_util/optional/ref/internal_traits.cc
>>>> new file mode 100644
>>>> index 00000000000..ef50da7e9fa
>>>> --- /dev/null
>>>> +++ b/libstdc++-v3/testsuite/20_util/optional/ref/internal_traits.cc
>>>> @@ -0,0 +1,11 @@
>>>> +// { dg-do compile { target c++26 }  }
>>>> +
>>>> +#include <optional>
>>>> +#include <variant>
>>>> +
>>>> +template<typename T>
>>>> +constexpr bool _Never_valueless
>>>> + = std::__detail::__variant::_Never_valueless_alt<T>::value;
>>>> +
>>>> +static_assert( _Never_valueless<std::optional<int&>> );
>>>> +static_assert( _Never_valueless<std::optional<const int&>> );
>>>> diff --git
>>>> a/libstdc++-v3/testsuite/20_util/optional/ref/make_optional/1.cc
>>>> b/libstdc++-v3/testsuite/20_util/optional/ref/make_optional/1.cc
>>>> new file mode 100644
>>>> index 00000000000..d9946d034ef
>>>> --- /dev/null
>>>> +++ b/libstdc++-v3/testsuite/20_util/optional/ref/make_optional/1.cc
>>>> @@ -0,0 +1,74 @@
>>>> +// { dg-do run { target c++20 }  }
>>>> +
>>>> +#include <optional>
>>>> +#include <utility>
>>>> +#include <testsuite_hooks.h>
>>>> +
>>>> +struct NonTrivial
>>>> +{
>>>> +  constexpr NonTrivial() {}
>>>> +  constexpr NonTrivial(NonTrivial const&) {};
>>>> +  constexpr ~NonTrivial() {};
>>>> +};
>>>> +
>>>> +template<typename T>
>>>> +struct Conv
>>>> +{
>>>> +  T t;
>>>> +
>>>> +  constexpr operator T() const noexcept
>>>> +  { return t; }
>>>> +};
>>>> +
>>>> +constexpr bool test()
>>>> +{
>>>> +  NonTrivial t;
>>>> +  const NonTrivial& ct = t;
>>>> +
>>>> +#if __cplusplus > 202302
>>>> +  auto o1 = std::make_optional<NonTrivial&>(t);
>>>> +  VERIFY( o1.has_value() );
>>>> +  VERIFY( &o1.value() == &t );
>>>> +
>>>> +  auto o2 = std::make_optional<const NonTrivial&>(t);
>>>> +  VERIFY( o2.has_value() );
>>>> +  VERIFY( &o2.value() == &t );
>>>> +
>>>> +  auto o3 = std::make_optional<const NonTrivial&>(ct);
>>>> +  VERIFY( o3.has_value() );
>>>> +  VERIFY( &o3.value() == &t );
>>>> +
>>>> +  Conv<NonTrivial&> rw(t);
>>>> +  auto o4 = std::make_optional<NonTrivial&>(rw);
>>>> +  VERIFY( o4.has_value() );
>>>> +  VERIFY( &o4.value() == &t );
>>>> +
>>>> +  auto o5 = std::make_optional<NonTrivial&>(std::as_const(rw));
>>>> +  VERIFY( o5.has_value() );
>>>> +  VERIFY( &o5.value() == &t );
>>>> +
>>>> +  auto o6 = std::make_optional<NonTrivial&>(Conv<NonTrivial&>(t));
>>>> +  VERIFY( o6.has_value() );
>>>> +  VERIFY( &o6.value() == &t );
>>>> +#else
>>>> +  auto o1 = std::make_optional<NonTrivial&>(t);
>>>> +  VERIFY( o1.has_value() );
>>>> +  VERIFY( &o1.value() != &t );
>>>> +
>>>> +  auto o3 = std::make_optional<const NonTrivial&>(ct);
>>>> +  VERIFY( o3.has_value() );
>>>> +  VERIFY( &o3.value() != &t );
>>>> +
>>>> +  auto o2 = std::make_optional<NonTrivial&&>(std::move(t));
>>>> +  VERIFY( o2.has_value() );
>>>> +  VERIFY( &o2.value() != &t );
>>>> +#endif
>>>> +
>>>> +  return true;
>>>> +}
>>>> +
>>>> +int main()
>>>> +{
>>>> +  test();
>>>> +  static_assert(test());
>>>> +}
>>>> diff --git
>>>> a/libstdc++-v3/testsuite/20_util/optional/ref/make_optional/from_args_neg.cc
>>>> b/libstdc++-v3/testsuite/20_util/optional/ref/make_optional/from_args_neg.cc
>>>> new file mode 100644
>>>> index 00000000000..6166c658c54
>>>> --- /dev/null
>>>> +++
>>>> b/libstdc++-v3/testsuite/20_util/optional/ref/make_optional/from_args_neg.cc
>>>> @@ -0,0 +1,43 @@
>>>> +// { dg-do compile { target c++17 }  }
>>>> +
>>>> +#include <optional>
>>>> +
>>>> +struct C {
>>>> +  C();
>>>> +  C(int);
>>>> +};
>>>> +C s(10);
>>>> +const C cs(1);
>>>> +
>>>> +template<typename T>
>>>> +using decay_pre26 =
>>>> +#if __cplusplus > 202302
>>>> +  T;
>>>> +#else
>>>> +  std::decay_t<T>;
>>>> +#endif
>>>> +
>>>> +auto z1 = std::make_optional<C&>();        // { dg-error "no matching
>>>> function for call" }
>>>> +auto z2 = std::make_optional<const C&>();  // { dg-error "no matching
>>>> function for call" }
>>>> +auto z3 = std::make_optional<C&&>();       // { dg-error "no matching
>>>> function for call" }
>>>> +auto z4 = std::make_optional<const C&&>(); // { dg-error "no matching
>>>> function for call" }
>>>> +
>>>> +auto o1 = std::make_optional<C&>(10);        // { dg-error "no
>>>> matching function for call" }
>>>> +auto o2 = std::make_optional<const C&>(10);  // { dg-error "from here"
>>>> }
>>>> +auto o3 = std::make_optional<C&&>(10);       // { dg-error "from here"
>>>> }
>>>> +auto o4 = std::make_optional<const C&&>(10); // { dg-error "from here"
>>>> }
>>>> +
>>>> +auto t1 = std::make_optional<C&>(10, 20);        // { dg-error "no
>>>> matching function for call" }
>>>> +auto t2 = std::make_optional<const C&>(10, 20);  // { dg-error "no
>>>> matching function for call" }
>>>> +auto t3 = std::make_optional<C&&>(10, 20);       // { dg-error "no
>>>> matching function for call" }
>>>> +auto t3 = std::make_optional<const C&&>(10, 20); // { dg-error "no
>>>> matching function for call" }
>>>> +
>>>> +// { dg-prune-output "no type named 'type' in 'struct std::enable_if" }
>>>> +// { dg-prune-output "type/value mismatch at argument 1 in template
>>>> parameter list" }
>>>> +// { dg-prune-output "in a union may not have reference type" }
>>>> +// { dg-prune-output "static assertion failed" }
>>>> +// { dg-prune-output "forming pointer to reference type" }
>>>> +// { dg-prune-output "cannot bind .* reference of type" }
>>>> +// { dg-prune-output "binding reference of type" }
>>>> +// { dg-prune-output "no matching function for call to 'std::optional"
>>>> }
>>>> +
>>>> diff --git
>>>> a/libstdc++-v3/testsuite/20_util/optional/ref/make_optional/from_lvalue_neg.cc
>>>> b/libstdc++-v3/testsuite/20_util/optional/ref/make_optional/from_lvalue_neg.cc
>>>> new file mode 100644
>>>> index 00000000000..aed6791a3ff
>>>> --- /dev/null
>>>> +++
>>>> b/libstdc++-v3/testsuite/20_util/optional/ref/make_optional/from_lvalue_neg.cc
>>>> @@ -0,0 +1,40 @@
>>>> +// { dg-do compile { target c++17 }  }
>>>> +
>>>> +#include <optional>
>>>> +#include <type_traits>
>>>> +
>>>> +struct C {
>>>> +  C();
>>>> +  C(int);
>>>> +};
>>>> +C s(10);
>>>> +const C cs(1);
>>>> +
>>>> +template<typename T>
>>>> +using decay_pre26 =
>>>> +#if __cplusplus > 202302
>>>> +  T;
>>>> +#else
>>>> +  std::decay_t<T>;
>>>> +#endif
>>>> +
>>>> +auto lr1 = std::make_optional<C&>(s);        // changed meaning
>>>> +static_assert( std::is_same_v< decltype(lr1),
>>>> std::optional<decay_pre26<C&>>> );
>>>> +auto lr2 = std::make_optional<const C&>(s);  // { dg-error "here" "" {
>>>> target c++23_down } }
>>>> +auto lr3 = std::make_optional<C&&>(s);       // { dg-error "no
>>>> matching function for call" }
>>>> +auto lr4 = std::make_optional<const C&&>(s); // { dg-error "no
>>>> matching function for call" }
>>>> +
>>>> +auto clr1 = std::make_optional<C&>(cs);        // { dg-error "no
>>>> matching function for call" }
>>>> +auto clr2 = std::make_optional<const C&>(cs);  // changed meaning
>>>> +static_assert( std::is_same_v< decltype(clr2),
>>>> std::optional<decay_pre26<const C&>>> );
>>>> +auto clr3 = std::make_optional<C&&>(cs);       // { dg-error "no
>>>> matching function for call" }
>>>> +auto clr3 = std::make_optional<const C&&>(cs); // { dg-error "no
>>>> matching function for call" }
>>>> +
>>>> +// { dg-prune-output "no type named 'type' in 'struct std::enable_if" }
>>>> +// { dg-prune-output "type/value mismatch at argument 1 in template
>>>> parameter list" }
>>>> +// { dg-prune-output "in a union may not have reference type" }
>>>> +// { dg-prune-output "static assertion failed" }
>>>> +// { dg-prune-output "forming pointer to reference type" }
>>>> +// { dg-prune-output "cannot bind .* reference of type" }
>>>> +// { dg-prune-output "binding reference of type" }
>>>> +// { dg-prune-output "no matching function for call to `std::optional"
>>>> }
>>>> diff --git
>>>> a/libstdc++-v3/testsuite/20_util/optional/ref/make_optional/from_rvalue_neg.cc
>>>> b/libstdc++-v3/testsuite/20_util/optional/ref/make_optional/from_rvalue_neg.cc
>>>> new file mode 100644
>>>> index 00000000000..22f669ceb68
>>>> --- /dev/null
>>>> +++
>>>> b/libstdc++-v3/testsuite/20_util/optional/ref/make_optional/from_rvalue_neg.cc
>>>> @@ -0,0 +1,38 @@
>>>> +// { dg-do compile { target c++17 }  }
>>>> +
>>>> +#include <optional>
>>>> +#include <type_traits>
>>>> +
>>>> +struct C {
>>>> +  C();
>>>> +  C(int);
>>>> +};
>>>> +C s(10);
>>>> +const C cs(1);
>>>> +
>>>> +template<typename T>
>>>> +using decay_pre26 =
>>>> +#if __cplusplus > 202302
>>>> +  T;
>>>> +#else
>>>> +  std::decay_t<T>;
>>>> +#endif
>>>> +
>>>> +auto p1 = std::make_optional<C&>(C(10));        // { dg-error "no
>>>> matching function for call" }
>>>> +auto p2 = std::make_optional<const C&>(C(10));  // { dg-error "from
>>>> here" }
>>>> +auto p3 = std::make_optional<C&&>(C(10));       // { dg-error "from
>>>> here" "" { target c++26 } }
>>>> +auto p4 = std::make_optional<const C&&>(C(10)); // { dg-error "from
>>>> here" }
>>>> +
>>>> +auto b1 = std::make_optional<C&>({10});        // { dg-error "no
>>>> matching function for call" }
>>>> +auto b2 = std::make_optional<const C&>({10});  // { dg-error "no
>>>> matching function for call" "" { target c++26 } }
>>>> +auto b3 = std::make_optional<C&&>({10});       // { dg-error "no
>>>> matching function for call" "" { target c++26 } }
>>>> +auto b4 = std::make_optional<const C&&>({10}); // { dg-error "no
>>>> matching function for call" "" { target c++26 } }
>>>> +
>>>> +// { dg-prune-output "no type named 'type' in 'struct std::enable_if" }
>>>> +// { dg-prune-output "type/value mismatch at argument 1 in template
>>>> parameter list" }
>>>> +// { dg-prune-output "in a union may not have reference type" }
>>>> +// { dg-prune-output "static assertion failed" }
>>>> +// { dg-prune-output "forming pointer to reference type" }
>>>> +// { dg-prune-output "cannot bind .* reference of type" }
>>>> +// { dg-prune-output "binding reference of type" }
>>>> +// { dg-prune-output "no matching function for call to 'std::optional"
>>>> }
>>>> diff --git a/libstdc++-v3/testsuite/20_util/optional/ref/monadic.cc
>>>> b/libstdc++-v3/testsuite/20_util/optional/ref/monadic.cc
>>>> new file mode 100644
>>>> index 00000000000..e8460c6528b
>>>> --- /dev/null
>>>> +++ b/libstdc++-v3/testsuite/20_util/optional/ref/monadic.cc
>>>> @@ -0,0 +1,192 @@
>>>> +// { dg-do run { target c++26 }  }
>>>> +
>>>> +#include <optional>
>>>> +#include <type_traits>
>>>> +#include <testsuite_hooks.h>
>>>> +#include <utility>
>>>> +
>>>> +struct NonMovable
>>>> +{
>>>> +  constexpr NonMovable() {}
>>>> +  NonMovable(NonMovable&&) = delete;
>>>> +};
>>>> +
>>>> +struct Tracker
>>>> +{
>>>> +  int copy = 0;
>>>> +  int move = 0;
>>>> +
>>>> +  Tracker() = default;
>>>> +
>>>> +  constexpr Tracker(Tracker const& o)
>>>> +  : copy(o.copy+1), move(o.move)
>>>> +  {}
>>>> +
>>>> +  constexpr Tracker(Tracker&& o)
>>>> +  : copy(o.copy), move(o.move+1)
>>>> +  {}
>>>> +
>>>> +  Tracker& operator=(Tracker) = delete;
>>>> +
>>>> +  void reset() {
>>>> +    copy = move = 0;
>>>> +  }
>>>> +};
>>>> +
>>>> +template<typename T>
>>>> +auto identity_of = []<typename U>(U&& t) -> std::optional<T>
>>>> +{
>>>> +  static_assert( std::is_same_v<T, U&&> );
>>>> +  VERIFY( t.copy == 0 );
>>>> +  VERIFY( t.move == 0 );
>>>> +  return std::optional<T>(t);
>>>> +};
>>>> +
>>>> +constexpr void
>>>> +test_and_then()
>>>> +{
>>>> +  std::optional<Tracker> t(std::in_place);
>>>> +  std::optional<Tracker&> rt(t);
>>>> +  std::optional<const Tracker&> rct(t);
>>>> +
>>>> +  auto r1 = t.and_then(identity_of<Tracker&>);
>>>> +  VERIFY( r1.has_value() );
>>>> +  VERIFY( &r1.value() == &t.value() );
>>>> +
>>>> +  auto r2 = rt.and_then(identity_of<Tracker&>);
>>>> +  VERIFY( r2.has_value() );
>>>> +  VERIFY( &r2.value() == &t.value() );
>>>> +
>>>> +  std::as_const(rt).and_then(identity_of<Tracker&>);
>>>> +  std::move(rt).and_then(identity_of<Tracker&>);
>>>> +
>>>> +  auto r4 = rct.and_then(identity_of<const Tracker&>);
>>>> +  VERIFY( r4.has_value() );
>>>> +  VERIFY( &r4.value() == &t.value() );
>>>> +
>>>> +  std::as_const(rct).and_then(identity_of<const Tracker&>);
>>>> +  std::move(rct).and_then(identity_of<const Tracker&>);
>>>> +
>>>> +  auto r5 = rt.and_then([](Tracker&) { return std::optional<int>(42);
>>>> });
>>>> +  static_assert( std::is_same_v<decltype(r5), std::optional<int>> );
>>>> +  VERIFY( r5.has_value() );
>>>> +  VERIFY( r5.value() == 42 );
>>>> +
>>>> +  auto r6 = rct.and_then([](const Tracker&) { return
>>>> std::optional<int>(); });
>>>> +  static_assert( std::is_same_v<decltype(r6), std::optional<int>> );
>>>> +  VERIFY( !r6.has_value() );
>>>> +
>>>> +  rct.reset();
>>>> +  auto r7 = rct.and_then([](const Tracker&) { VERIFY(false); return
>>>> std::optional<int>(42); });
>>>> +  static_assert( std::is_same_v<decltype(r7), std::optional<int>> );
>>>> +  VERIFY( !r7.has_value() );
>>>> +
>>>> +  rt.reset();
>>>> +  auto r8 = rt.and_then([](Tracker&) { VERIFY(false); return
>>>> std::optional<int>(); });
>>>> +  static_assert( std::is_same_v<decltype(r8), std::optional<int>> );
>>>> +  VERIFY( !r8.has_value() );
>>>> +}
>>>> +
>>>> +template<typename T>
>>>> +constexpr void
>>>> +test_or_else()
>>>> +{
>>>> +  T t, u;
>>>> +
>>>> +  std::optional<T&> ot(t);
>>>> +  auto r1 = ot.or_else([&] { VERIFY(false); return
>>>> std::optional<T&>(u); });
>>>> +  VERIFY( &ot.value() == &t );
>>>> +  VERIFY( r1.has_value() );
>>>> +  VERIFY( &r1.value() == &t );
>>>> +  auto r2 = std::move(ot).or_else([&] { VERIFY(false); return
>>>> std::optional<T&>(); });
>>>> +  VERIFY( &ot.value() == &t );
>>>> +  VERIFY( r2.has_value() );
>>>> +  VERIFY( &r2.value() == &t );
>>>> +
>>>> +  ot.reset();
>>>> +  auto r3 = ot.or_else([&] { return std::optional<T&>(u); });
>>>> +  VERIFY( !ot.has_value() );
>>>> +  VERIFY( r3.has_value() );
>>>> +  VERIFY( &r3.value() == &u );
>>>> +  auto r4 = std::move(ot).or_else([] { return std::optional<T&>(); });
>>>> +  VERIFY( !ot.has_value() );
>>>> +  VERIFY( !r4.has_value() );
>>>> +}
>>>> +
>>>> +constexpr void
>>>> +test_transform()
>>>> +{
>>>> +  std::optional<Tracker> t(std::in_place);
>>>> +
>>>> +  auto r1 = t.transform(&Tracker::copy);
>>>> +  static_assert( std::is_same_v<decltype(r1), std::optional<int&>> );
>>>> +  VERIFY( r1.has_value() );
>>>> +  VERIFY( &r1.value() == &t->copy );
>>>> +  auto r2 = std::as_const(t).transform(&Tracker::move);
>>>> +  static_assert( std::is_same_v<decltype(r2), std::optional<const
>>>> int&>> );
>>>> +  VERIFY( r2.has_value() );
>>>> +  VERIFY( &r2.value() == &t->move );
>>>> +
>>>> +  std::optional<Tracker&> rt(t);
>>>> +  auto r3 = rt.transform(&Tracker::copy);
>>>> +  static_assert( std::is_same_v<decltype(r3), std::optional<int&>> );
>>>> +  VERIFY( r3.has_value() );
>>>> +  VERIFY( &r3.value() == &t->copy );
>>>> +  auto r4 = std::as_const(rt).transform(&Tracker::copy);
>>>> +  static_assert( std::is_same_v<decltype(r4), std::optional<int&>> );
>>>> +  VERIFY( r4.has_value() );
>>>> +  VERIFY( &r4.value() == &t->copy );
>>>> +  auto r5 = std::move(rt).transform(&Tracker::copy);
>>>> +  static_assert( std::is_same_v<decltype(r5), std::optional<int&>> );
>>>> +  VERIFY( r5.has_value() );
>>>> +  VERIFY( &r5.value() == &t->copy );
>>>> +
>>>> +  auto r6 = rt.transform([] (Tracker& t) { return 10; });
>>>> +  static_assert( std::is_same_v<decltype(r6), std::optional<int>> );
>>>> +  VERIFY( r6.has_value() );
>>>> +  VERIFY( &r6.value() != &t->copy );
>>>> +  VERIFY( r6.value() == 10 );
>>>> +
>>>> +  auto r7 = rt.transform([] (Tracker& t) { return NonMovable(); });
>>>> +  static_assert( std::is_same_v<decltype(r7),
>>>> std::optional<NonMovable>> );
>>>> +  VERIFY( r7.has_value() );
>>>> +
>>>> +  rt.reset();
>>>> +  auto r8 = rt.transform([] (Tracker& t) { VERIFY(false); return 42;
>>>> });
>>>> +  static_assert( std::is_same_v<decltype(r8), std::optional<int>> );
>>>> +  VERIFY( !r8.has_value() );
>>>> +
>>>> +  std::optional<const Tracker&> crt(t);
>>>> +  auto r9 = crt.transform(&Tracker::copy);
>>>> +  static_assert( std::is_same_v<decltype(r9), std::optional<const
>>>> int&>> );
>>>> +  VERIFY( r9.has_value() );
>>>> +  VERIFY( &r9.value() == &t->copy );
>>>> +  auto r10 = std::as_const(crt).transform(&Tracker::copy);
>>>> +  static_assert( std::is_same_v<decltype(r10), std::optional<const
>>>> int&>> );
>>>> +  VERIFY( r10.has_value() );
>>>> +  VERIFY( &r10.value() == &t->copy );
>>>> +  auto r11 = std::move(crt).transform(&Tracker::copy);
>>>> +  static_assert( std::is_same_v<decltype(r11), std::optional<const
>>>> int&>> );
>>>> +  VERIFY( r11.has_value() );
>>>> +  VERIFY( &r11.value() == &t->copy );
>>>> +
>>>> +  crt.reset();
>>>> +  auto r12 = rt.transform([] (Tracker& t) { VERIFY(false); return 42;
>>>> });
>>>> +  static_assert( std::is_same_v<decltype(r12), std::optional<int>> );
>>>> +  VERIFY( !r12.has_value() );
>>>> +}
>>>> +
>>>> +int main()
>>>> +{
>>>> +  auto test_all = [] {
>>>> +    test_and_then();
>>>> +    test_transform();
>>>> +    test_or_else<Tracker>();
>>>> +    test_or_else<const Tracker>();
>>>> +    test_or_else<NonMovable>();
>>>> +    return true;
>>>> +  };
>>>> +
>>>> +  test_all();
>>>> +  static_assert(test_all());
>>>> +}
>>>> diff --git a/libstdc++-v3/testsuite/20_util/optional/ref/relops.cc
>>>> b/libstdc++-v3/testsuite/20_util/optional/ref/relops.cc
>>>> new file mode 100644
>>>> index 00000000000..e0b30c8e898
>>>> --- /dev/null
>>>> +++ b/libstdc++-v3/testsuite/20_util/optional/ref/relops.cc
>>>> @@ -0,0 +1,229 @@
>>>> +// { dg-do run { target c++26 }  }
>>>> +
>>>> +#include <optional>
>>>> +#include <functional>
>>>> +#include <testsuite_hooks.h>
>>>> +#include <type_traits>
>>>> +
>>>> +template<typename T, typename H = std::hash<T>>
>>>> +constexpr bool has_disabled_hash
>>>> + = !std::is_default_constructible_v<H>
>>>> + && !std::is_copy_constructible_v<H>
>>>> + && !std::is_move_constructible_v<H>
>>>> + && !std::is_copy_assignable_v<H>
>>>> + && !std::is_move_assignable_v<H>;
>>>> +
>>>> +static_assert(has_disabled_hash<std::optional<int&>>);
>>>> +static_assert(has_disabled_hash<std::optional<const int&>>);
>>>> +
>>>> +template<typename T, typename V>
>>>> +constexpr void
>>>> +test_compare_val(V& l, V& h)
>>>> +{
>>>> +  std::optional<T> t;
>>>> +
>>>> +  VERIFY( !(t == l) );
>>>> +  VERIFY(  (t != l) );
>>>> +  VERIFY(  (t <  l) );
>>>> +  VERIFY(  (t <= l) );
>>>> +  VERIFY( !(t >  l) );
>>>> +  VERIFY( !(t >= l) );
>>>> +  VERIFY( (t <=> l) < 0 );
>>>> +
>>>> +  VERIFY( !(l == t) );
>>>> +  VERIFY(  (l != t) );
>>>> +  VERIFY( !(l <  t) );
>>>> +  VERIFY( !(l <= t) );
>>>> +  VERIFY(  (l >  t) );
>>>> +  VERIFY(  (l >= t) );
>>>> +  VERIFY( (l <=> t) > 0 );
>>>> +
>>>> +  t.emplace(l);
>>>> +  VERIFY(  (t == l) );
>>>> +  VERIFY( !(t != l) );
>>>> +  VERIFY( !(t <  l) );
>>>> +  VERIFY(  (t <= l) );
>>>> +  VERIFY( !(t >  l) );
>>>> +  VERIFY(  (t >= l) );
>>>> +  VERIFY( (t <=> l) == 0 );
>>>> +
>>>> +  VERIFY(  (l == t) );
>>>> +  VERIFY( !(l != t) );
>>>> +  VERIFY( !(l <  t) );
>>>> +  VERIFY(  (l <= t) );
>>>> +  VERIFY( !(l >  t) );
>>>> +  VERIFY(  (l >= t) );
>>>> +  VERIFY( (t <=> l) == 0 );
>>>> +
>>>> +  t.emplace(h);
>>>> +  VERIFY( !(t == l) );
>>>> +  VERIFY(  (t != l) );
>>>> +  VERIFY( !(t <  l) );
>>>> +  VERIFY( !(t <= l) );
>>>> +  VERIFY(  (t >  l) );
>>>> +  VERIFY(  (t >= l) );
>>>> +  VERIFY( (t <=> l) > 0 );
>>>> +
>>>> +  VERIFY( !(l == t) );
>>>> +  VERIFY(  (l != t) );
>>>> +  VERIFY(  (l <  t) );
>>>> +  VERIFY(  (l <= t) );
>>>> +  VERIFY( !(l >  t) );
>>>> +  VERIFY( !(l >= t) );
>>>> +  VERIFY( (l <=> t) < 0 );
>>>> +}
>>>> +
>>>> +template<typename T, typename U, typename V>
>>>> +constexpr void
>>>> +test_compare_opts(V& l, V& h)
>>>> +{
>>>> +  std::optional<T> t;
>>>> +  std::optional<U> u;
>>>> +
>>>> +  VERIFY(  (t == u) );
>>>> +  VERIFY( !(t != u) );
>>>> +  VERIFY( !(t <  u) );
>>>> +  VERIFY(  (t <= u) );
>>>> +  VERIFY( !(t >  u) );
>>>> +  VERIFY(  (t >= u) );
>>>> +  VERIFY( (t <=> u) == 0 );
>>>> +
>>>> +  t.emplace(l);
>>>> +  VERIFY( !(t == u) );
>>>> +  VERIFY(  (t != u) );
>>>> +  VERIFY( !(t <  u) );
>>>> +  VERIFY( !(t <= u) );
>>>> +  VERIFY(  (t >  u) );
>>>> +  VERIFY(  (t >= u) );
>>>> +  VERIFY( (t <=> u) > 0 );
>>>> +
>>>> +  u.emplace(l);
>>>> +  VERIFY(  (t == u) );
>>>> +  VERIFY( !(t != u) );
>>>> +  VERIFY( !(t <  u) );
>>>> +  VERIFY(  (t <= u) );
>>>> +  VERIFY( !(t >  u) );
>>>> +  VERIFY(  (t <= u) );
>>>> +  VERIFY( (t <=> u) == 0 );
>>>> +
>>>> +  u.emplace(h);
>>>> +  VERIFY( !(t == u) );
>>>> +  VERIFY(  (t != u) );
>>>> +  VERIFY(  (t <  u) );
>>>> +  VERIFY(  (t <= u) );
>>>> +  VERIFY( !(t >  u) );
>>>> +  VERIFY( !(t >= u) );
>>>> +  VERIFY( (t <=> u) < 0 );
>>>> +
>>>> +  t.reset();
>>>> +  u.emplace(l);
>>>> +  VERIFY( !(t == u) );
>>>> +  VERIFY(  (t != u) );
>>>> +  VERIFY(  (t <  u) );
>>>> +  VERIFY(  (t <= u) );
>>>> +  VERIFY( !(t >  u) );
>>>> +  VERIFY( !(t >= u) );
>>>> +  VERIFY( (t <=> u) < 0 );
>>>> +
>>>> +  t.emplace(h);
>>>> +  VERIFY( !(t == u) );
>>>> +  VERIFY(  (t != u) );
>>>> +  VERIFY( !(t <  u) );
>>>> +  VERIFY( !(t <= u) );
>>>> +  VERIFY(  (t >  u) );
>>>> +  VERIFY(  (t >= u) );
>>>> +  VERIFY( (t <=> u) > 0 );
>>>> +}
>>>> +
>>>> +template<typename V>
>>>> +constexpr void
>>>> +test_compare(V l, V h)
>>>> +{
>>>> +  test_compare_val<V&>(l, h);
>>>> +  test_compare_val<const V&>(l, h);
>>>> +
>>>> +  test_compare_opts<V&, V&>(l, h);
>>>> +  test_compare_opts<V, V&>(l, h);
>>>> +  test_compare_opts<V&, V>(l, h);
>>>> +
>>>> +  test_compare_opts<const V&, const V&>(l, h);
>>>> +  test_compare_opts<V, const V&>(l, h);
>>>> +  test_compare_opts<const V&, V>(l, h);
>>>> +
>>>> +  test_compare_opts<V&, const V&>(l, h);
>>>> +  test_compare_opts<const V&, V&>(l, h);
>>>> +}
>>>> +
>>>> +struct TreeWay
>>>> +{
>>>> +  int v;
>>>> +  friend auto operator<=>(TreeWay, TreeWay) = default;
>>>> +};
>>>> +
>>>> +struct Other
>>>> +{
>>>> +  int v;
>>>> +
>>>> +  constexpr Other(int p) : v(p) {}
>>>> +  constexpr Other(TreeWay p) : v(p.v) {}
>>>> +
>>>> +  friend bool operator==(Other, Other) = default;
>>>> +  friend auto operator<=>(Other, Other) = default;
>>>> +
>>>> +  friend constexpr bool
>>>> +  operator==(const Other& lhs, const TreeWay& rhs)
>>>> +  { return lhs.v == rhs.v; }
>>>> +
>>>> +  friend constexpr std::strong_ordering
>>>> +  operator<=>(const Other& lhs, const TreeWay& rhs)
>>>> +  { return lhs.v <=> rhs.v; }
>>>> +};
>>>> +
>>>> +constexpr void
>>>> +test_heterogeneus_cmp()
>>>> +{
>>>> +  TreeWay l{10};
>>>> +  Other h{20};
>>>> +
>>>> +  std::optional<TreeWay&> t;
>>>> +  std::optional<const Other&> u;
>>>> +
>>>> +  VERIFY(  (t == u) );
>>>> +  VERIFY( !(t != u) );
>>>> +  VERIFY( !(t <  u) );
>>>> +  VERIFY(  (t <= u) );
>>>> +  VERIFY( !(t >  u) );
>>>> +  VERIFY(  (t >= u) );
>>>> +  VERIFY( (t <=> u) == 0 );
>>>> +
>>>> +  t.emplace(l);
>>>> +  VERIFY( !(t == u) );
>>>> +  VERIFY(  (t != u) );
>>>> +  VERIFY( !(t <  u) );
>>>> +  VERIFY( !(t <= u) );
>>>> +  VERIFY(  (t >  u) );
>>>> +  VERIFY(  (t >= u) );
>>>> +  VERIFY( (t <=> u) > 0 );
>>>> +
>>>> +  u.emplace(h);
>>>> +  VERIFY( !(t == u) );
>>>> +  VERIFY(  (t != u) );
>>>> +  VERIFY(  (t <  u) );
>>>> +  VERIFY(  (t <= u) );
>>>> +  VERIFY( !(t >  u) );
>>>> +  VERIFY( !(t >= u) );
>>>> +  VERIFY( (t <=> u) < 0 );
>>>> +}
>>>> +
>>>> +int main()
>>>> +{
>>>> +  auto test_all = [] {
>>>> +    test_compare(2, 5);
>>>> +    test_compare(TreeWay{11}, TreeWay{12});
>>>> +    test_heterogeneus_cmp();
>>>> +    return true;
>>>> +  };
>>>> +
>>>> +  test_all();
>>>> +  static_assert(test_all());
>>>> +}
>>>> diff --git
>>>> a/libstdc++-v3/testsuite/20_util/optional/relops/constrained.cc
>>>> b/libstdc++-v3/testsuite/20_util/optional/relops/constrained.cc
>>>> index 3e393257928..ec47552c475 100644
>>>> --- a/libstdc++-v3/testsuite/20_util/optional/relops/constrained.cc
>>>> +++ b/libstdc++-v3/testsuite/20_util/optional/relops/constrained.cc
>>>> @@ -8,8 +8,8 @@
>>>>  # error "Feature-test macro for constrained_equality has wrong value"
>>>>  #endif
>>>>
>>>> -template<typename T, typename U = T>
>>>> -concept eq_comparable
>>>> +template<typename T, typename U>
>>>> +concept eq_comparable_impl
>>>>  = requires (const std::optional<T>& t, const std::optional<U>& u) {
>>>>    t == u;
>>>>    *t == u;
>>>> @@ -17,7 +17,19 @@ concept eq_comparable
>>>>  };
>>>>
>>>>  template<typename T, typename U = T>
>>>> -concept ne_comparable
>>>> +concept eq_comparable =
>>>> +  eq_comparable_impl<T, U>
>>>> +#if __cplusplus > 202302l
>>>> +  && eq_comparable_impl<T&, U&>
>>>> +  && eq_comparable_impl<T const&, U const&>
>>>> +  && eq_comparable_impl<T const&, U&>
>>>> +  && eq_comparable_impl<T, U const&>
>>>> +  && eq_comparable_impl<T&, U>
>>>> +#endif
>>>> +;
>>>> +
>>>> +template<typename T, typename U>
>>>> +concept ne_comparable_impl
>>>>  = requires (const std::optional<T>& t, const std::optional<U>& u) {
>>>>    t != u;
>>>>    *t != u;
>>>> @@ -25,7 +37,19 @@ concept ne_comparable
>>>>  };
>>>>
>>>>  template<typename T, typename U = T>
>>>> -concept lt_comparable
>>>> +concept ne_comparable =
>>>> +  ne_comparable_impl<T, U>
>>>> +#if __cplusplus > 202302l
>>>> +  && ne_comparable_impl<T&, U&>
>>>> +  && ne_comparable_impl<T const&, U const&>
>>>> +  && ne_comparable_impl<T const&, U&>
>>>> +  && ne_comparable_impl<T, U const&>
>>>> +  && ne_comparable_impl<T&, U>
>>>> +#endif
>>>> +;
>>>> +
>>>> +template<typename T, typename U>
>>>> +concept lt_comparable_impl
>>>>  = requires (const std::optional<T>& t, const std::optional<U>& u) {
>>>>    t < u;
>>>>    *t < u;
>>>> @@ -33,7 +57,19 @@ concept lt_comparable
>>>>  };
>>>>
>>>>  template<typename T, typename U = T>
>>>> -concept le_comparable
>>>> +concept lt_comparable =
>>>> +  lt_comparable_impl<T, U>
>>>> +#if __cplusplus > 202302l
>>>> +  && lt_comparable_impl<T&, U&>
>>>> +  && lt_comparable_impl<T const&, U const&>
>>>> +  && lt_comparable_impl<T const&, U&>
>>>> +  && lt_comparable_impl<T, U const&>
>>>> +  && lt_comparable_impl<T&, U>
>>>> +#endif
>>>> +;
>>>> +
>>>> +template<typename T, typename U>
>>>> +concept le_comparable_impl
>>>>  = requires (const std::optional<T>& t, const std::optional<U>& u) {
>>>>    t <= u;
>>>>    *t <= u;
>>>> @@ -41,7 +77,19 @@ concept le_comparable
>>>>  };
>>>>
>>>>  template<typename T, typename U = T>
>>>> -concept gt_comparable
>>>> +concept le_comparable =
>>>> +  le_comparable_impl<T, U>
>>>> +#if __cplusplus > 202302l
>>>> +  && le_comparable_impl<T&, U&>
>>>> +  && le_comparable_impl<T const&, U const&>
>>>> +  && le_comparable_impl<T const&, U&>
>>>> +  && le_comparable_impl<T, U const&>
>>>> +  && le_comparable_impl<T&, U>
>>>> +#endif
>>>> +;
>>>> +
>>>> +template<typename T, typename U>
>>>> +concept gt_comparable_impl
>>>>  = requires (const std::optional<T>& t, const std::optional<U>& u) {
>>>>    t > u;
>>>>    *t > u;
>>>> @@ -49,13 +97,37 @@ concept gt_comparable
>>>>  };
>>>>
>>>>  template<typename T, typename U = T>
>>>> -concept ge_comparable
>>>> +concept gt_comparable =
>>>> +  gt_comparable_impl<T, U>
>>>> +#if __cplusplus > 202302l
>>>> +  && gt_comparable_impl<T&, U&>
>>>> +  && gt_comparable_impl<T const&, U const&>
>>>> +  && gt_comparable_impl<T const&, U&>
>>>> +  && gt_comparable_impl<T, U const&>
>>>> +  && gt_comparable_impl<T&, U>
>>>> +#endif
>>>> +;
>>>> +
>>>> +template<typename T, typename U>
>>>> +concept ge_comparable_impl
>>>>  = requires (const std::optional<T>& t, const std::optional<U>& u) {
>>>>    t >= u;
>>>>    *t >= u;
>>>>    t >= *u;
>>>>  };
>>>>
>>>> +template<typename T, typename U = T>
>>>> +concept ge_comparable =
>>>> +  ge_comparable_impl<T, U>
>>>> +#if __cplusplus > 202302l
>>>> +  && ge_comparable_impl<T&, U&>
>>>> +  && ge_comparable_impl<T const&, U const&>
>>>> +  && ge_comparable_impl<T const&, U&>
>>>> +  && ge_comparable_impl<T, U const&>
>>>> +  && ge_comparable_impl<T&, U>
>>>> +#endif
>>>> +;
>>>> +
>>>>  static_assert( eq_comparable<int> );
>>>>  static_assert( ne_comparable<int> );
>>>>  static_assert( lt_comparable<int> );
>>>> diff --git a/libstdc++-v3/testsuite/20_util/optional/requirements.cc
>>>> b/libstdc++-v3/testsuite/20_util/optional/requirements.cc
>>>> index 68e59057b5e..9e8cf83da44 100644
>>>> --- a/libstdc++-v3/testsuite/20_util/optional/requirements.cc
>>>> +++ b/libstdc++-v3/testsuite/20_util/optional/requirements.cc
>>>> @@ -26,8 +26,10 @@
>>>>  # error "Feature test macro for optional has wrong value in <optional>"
>>>>  #elif __cplusplus == 202002L && __cpp_lib_optional != 202106L
>>>>  # error "Feature test macro for optional has wrong value for C++20 in
>>>> <optional>"
>>>> -#elif __cplusplus > 202002L && __cpp_lib_optional != 202110L
>>>> -# error "Feature test macro for optional has wrong value for C++23 in
>>>> <version>"
>>>> +#elif __cplusplus == 202302L && __cpp_lib_optional != 202110L
>>>> +# error "Feature test macro for optional has wrong value for C++23 in
>>>> <optional>"
>>>> +#elif __cplusplus > 202302L && __cpp_lib_optional != 202506L
>>>> +# error "Feature test macro for optional has wrong value for C++26 in
>>>> <optional>"
>>>>  #endif
>>>>
>>>>  #include <testsuite_hooks.h>
>>>> diff --git
>>>> a/libstdc++-v3/testsuite/20_util/optional/requirements_neg.cc
>>>> b/libstdc++-v3/testsuite/20_util/optional/requirements_neg.cc
>>>> index 688c305803e..142fbbfc515 100644
>>>> --- a/libstdc++-v3/testsuite/20_util/optional/requirements_neg.cc
>>>> +++ b/libstdc++-v3/testsuite/20_util/optional/requirements_neg.cc
>>>> @@ -2,17 +2,32 @@
>>>>
>>>>  #include <optional>
>>>>
>>>> +// C++ < 26:
>>>>  // T shall be a type other than cv in_place_t or cv nullopt_t
>>>>  // that meets the Cpp17Destructible requirements
>>>> +// C++ >= 26:
>>>> +// A type X is a valid contained type for optional if X is an lvalue
>>>> reference
>>>> +// type or a complete non-array object type, and remove_cvref_t<X> is
>>>> a type
>>>> +// other than in_place_t or nullopt_t. If a specialization of optional
>>>> +// is instantiated with a type T that is not a valid contained type for
>>>> +// optional, the program is ill-formed. If T is an object type,
>>>> +// T shall meet the Cpp17Destructible requirements
>>>>
>>>>  std::optional<std::nullopt_t> o1;        // { dg-error "here" }
>>>>  std::optional<const std::nullopt_t> o2;  // { dg-error "here" }
>>>>  std::optional<std::in_place_t> o3;       // { dg-error "here" }
>>>>  std::optional<const std::in_place_t> o4; // { dg-error "here" }
>>>> -std::optional<int&> o5;                  // { dg-error "here" }
>>>> +std::optional<int&> o5;                  // { dg-error "here"
>>>> "optional<T&> is a C++26 feature" { target c++23_down } }
>>>>  std::optional<int[1]> o6;                // { dg-error "here" }
>>>>  std::optional<int[]> o7;                 // { dg-error "here" }
>>>>  std::optional<int()> o8;                 // { dg-error "here" }
>>>> +std::optional<const int &> o9;           // { dg-error "here"
>>>> "optional<T&> is a C++26 feature" { target c++23_down } }
>>>> +std::optional<std::in_place_t &> o10;    // { dg-error "here" }
>>>> +std::optional<const std::in_place_t &> o11; // { dg-error "here" }
>>>> +std::optional<std::nullopt_t &> o12;     // { dg-error "here" }
>>>> +std::optional<const std::nullopt_t &> o13; // { dg-error "here" }
>>>> +std::optional<int &&> o14;               // { dg-error "here" }
>>>> +std::optional<const int &&> o15;         // { dg-error "here" }
>>>>
>>>>  // { dg-error "static assertion failed" "" { target *-*-* } 0 }
>>>>
>>>> diff --git a/libstdc++-v3/testsuite/20_util/optional/version.cc
>>>> b/libstdc++-v3/testsuite/20_util/optional/version.cc
>>>> index ba44aa52535..ae9339a01af 100644
>>>> --- a/libstdc++-v3/testsuite/20_util/optional/version.cc
>>>> +++ b/libstdc++-v3/testsuite/20_util/optional/version.cc
>>>> @@ -9,8 +9,10 @@
>>>>  # error "Feature test macro for optional has wrong value for C++17 in
>>>> <version>"
>>>>  #elif __cplusplus == 202002L && __cpp_lib_optional != 202106L
>>>>  # error "Feature test macro for optional has wrong value for C++20 in
>>>> <version>"
>>>> -#elif __cplusplus > 202002L && __cpp_lib_optional != 202110L
>>>> +#elif __cplusplus == 202302L && __cpp_lib_optional != 202110L
>>>>  # error "Feature test macro for optional has wrong value for C++23 in
>>>> <version>"
>>>> +#elif __cplusplus > 202302L && __cpp_lib_optional != 202506L
>>>> +# error "Feature test macro for optional has wrong value for C++26 in
>>>> <version>"
>>>>  #endif
>>>>
>>>>  #if __cplusplus >= 202302L
>>>> --
>>>> 2.51.0
>>>>
>>>>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://gcc.gnu.org/pipermail/libstdc++/attachments/20251020/86745bd2/attachment-0001.htm>


More information about the Libstdc++ mailing list