This patch adds a new make_optional<_Tp>(type_identity<_Tp>&&)overload,
to address regression on make_optional<T> with non-reference types caused
by PR121748.

Using type_identity makes _Tp non-deducible, ensuring this overload is only
viable when the constructed type is explicitly spelled out. This overload
is constrained to non-reference types, preventing it from ceating an
optional<T&> referencing a temporary object.

        PR libstdc++/121748

libstdc++-v3/ChangeLog:

        * include/std/optional (std::make_optional(type_identity<_Tp>&&)):
        Define.
        * testsuite/20_util/optional/make_optional-2.cc: Add tests.
        * testsuite/20_util/optional/make_optional_neg.cc: Removed.
---
I am not convinced that this is something we should fix, as equivalently users
can just write std::optional<T>({args...}) in all standards. For 
non-initializer list
cases, std::make_optional<T>(args...) will avoid move.
Posting it to illustrate that the regressions is easily addressable.

Tested on x86_64-linux locally. *optional* test also tested with all standard 
modes.


 libstdc++-v3/include/std/optional             | 10 ++++++++++
 .../20_util/optional/make_optional-2.cc       |  8 ++++++--
 .../20_util/optional/make_optional_neg.cc     | 20 -------------------
 3 files changed, 16 insertions(+), 22 deletions(-)
 delete mode 100644 libstdc++-v3/testsuite/20_util/optional/make_optional_neg.cc

diff --git a/libstdc++-v3/include/std/optional 
b/libstdc++-v3/include/std/optional
index e6f3a985f50..961ec5c8508 100644
--- a/libstdc++-v3/include/std/optional
+++ b/libstdc++-v3/include/std/optional
@@ -2075,6 +2075,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     noexcept(is_nothrow_constructible_v<optional<decay_t<_Tp>>, _Tp>)
     { return optional<decay_t<_Tp>>( std::forward<_Tp>(__t) ); }
 
+#if __cpp_lib_optional >= 202506L
+  // Devation, fix regression on make_optional<T>({...})
+  template<typename _Tp>
+    requires (!is_reference_v<_Tp>) && is_move_constructible_v<_Tp>
+    constexpr std::optional<_Tp>
+    make_optional(type_identity_t<_Tp>&& __t)
+    noexcept(is_nothrow_move_constructible_v<_Tp>)
+    { return optional<_Tp>( std::move(__t) ); }
+#endif
+
   template<typename _Tp, typename... _Args>
     constexpr
     enable_if_t<is_constructible_v<_Tp, _Args...>,
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 0aa2ac5ed93..5c210f8a529 100644
--- a/libstdc++-v3/testsuite/20_util/optional/make_optional-2.cc
+++ b/libstdc++-v3/testsuite/20_util/optional/make_optional-2.cc
@@ -70,9 +70,7 @@ 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 );
@@ -94,3 +92,9 @@ static_assert( noexcept(std::make_optional<Cont>({1,2}, 1)) );
 static_assert( can_make_optional3<Cont, char*>::value );
 static_assert( ! noexcept(std::make_optional<Cont>({1,2}, "")) );
 static_assert( !can_make_optional3<Cont, int*>::value );
+
+struct S { int x; int* p; };
+int v;
+
+static_assert( noexcept(std::make_optional<S>({1, &v})) );
+
diff --git a/libstdc++-v3/testsuite/20_util/optional/make_optional_neg.cc 
b/libstdc++-v3/testsuite/20_util/optional/make_optional_neg.cc
deleted file mode 100644
index 09499477233..00000000000
--- a/libstdc++-v3/testsuite/20_util/optional/make_optional_neg.cc
+++ /dev/null
@@ -1,20 +0,0 @@
-// { 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" }
-- 
2.51.0

Reply via email to