[libcxx-commits] [libcxx] [libc++] LWG3627: Inconsistent specifications for `std::make_optional` overloads (PR #173466)
A. Jiang via libcxx-commits
libcxx-commits at lists.llvm.org
Wed Dec 24 00:11:08 PST 2025
https://github.com/frederick-vs-ja created https://github.com/llvm/llvm-project/pull/173466
It should be sufficient to use `is_constructible_v<decay_t<T>, T>` in the constraints, because the `const optional<U>&`/`optional<U>&&` constructors are sufficiently constrained.
Drive-by: Refactor `libcxx/test/std/utilities/optional/optional.specalg/make_optional.pass.cpp` to run more cases during constant evaluation.
Fixes #171309.
>From 3787c6a573736899c892fe268d5af6b54846f7f2 Mon Sep 17 00:00:00 2001
From: "A. Jiang" <de34 at live.cn>
Date: Wed, 24 Dec 2025 15:54:34 +0800
Subject: [PATCH] [libc++] LWG3627: Inconsistent specifications for
`std::make_optional` overloads
It should be sufficient to use `is_constructible_v<decay_t<T>, T>` in
the constraints, because the `const optional<U>&`/`optional<U>&&`
constructors are sufficiently constrained.
Drive-by: Refactor `libcxx/test/std/utilities/optional/optional.specalg/make_optional.pass.cpp`
to run more cases during constant evaluation.
---
libcxx/docs/Status/Cxx2cIssues.csv | 2 +-
libcxx/include/optional | 3 +-
.../optional.specalg/make_optional.pass.cpp | 101 ++++++++++++------
3 files changed, 73 insertions(+), 33 deletions(-)
diff --git a/libcxx/docs/Status/Cxx2cIssues.csv b/libcxx/docs/Status/Cxx2cIssues.csv
index 76015ea53d0ba..eed6e9bcf6a65 100644
--- a/libcxx/docs/Status/Cxx2cIssues.csv
+++ b/libcxx/docs/Status/Cxx2cIssues.csv
@@ -150,7 +150,7 @@
"`LWG3090 <https://wg21.link/LWG3090>`__","What is ยง[time.duration.cons]p4's ""no overflow is induced in the conversion"" intended to mean?","2025-11 (Kona)","","","`#171302 <https://github.com/llvm/llvm-project/issues/171302>`__",""
"`LWG3343 <https://wg21.link/LWG3343>`__","Ordering of calls to ``unlock()`` and ``notify_all()`` in Effects element of ``notify_all_at_thread_exit()`` should be reversed","2025-11 (Kona)","|Complete|","16","`#105356 <https://github.com/llvm/llvm-project/issues/105356>`__",""
"`LWG3454 <https://wg21.link/LWG3454>`__","``pointer_traits::pointer_to`` should be ``constexpr``","2025-11 (Kona)","","","`#171307 <https://github.com/llvm/llvm-project/issues/171307>`__",""
-"`LWG3627 <https://wg21.link/LWG3627>`__","Inconsistent specifications for ``std::make_optional`` overloads","2025-11 (Kona)","","","`#171309 <https://github.com/llvm/llvm-project/issues/171309>`__",""
+"`LWG3627 <https://wg21.link/LWG3627>`__","Inconsistent specifications for ``std::make_optional`` overloads","2025-11 (Kona)","|Complete|","22","`#171309 <https://github.com/llvm/llvm-project/issues/171309>`__",""
"`LWG4015 <https://wg21.link/LWG4015>`__","LWG 3973 broke const overloads of ``std::optional`` monadic operations","2025-11 (Kona)","","","`#171310 <https://github.com/llvm/llvm-project/issues/171310>`__",""
"`LWG4020 <https://wg21.link/LWG4020>`__","``extents::index-cast`` weirdness","2025-11 (Kona)","","","`#171311 <https://github.com/llvm/llvm-project/issues/171311>`__",""
"`LWG4136 <https://wg21.link/LWG4136>`__","Specify behavior of [linalg] Hermitian algorithms on diagonal with nonzero imaginary part","2025-11 (Kona)","","","`#171312 <https://github.com/llvm/llvm-project/issues/171312>`__",""
diff --git a/libcxx/include/optional b/libcxx/include/optional
index 440fdf73a4310..949c512cb719c 100644
--- a/libcxx/include/optional
+++ b/libcxx/include/optional
@@ -1506,7 +1506,8 @@ template <
# if _LIBCPP_STD_VER >= 26
__make_optional_barrier_tag = __make_optional_barrier_tag{},
# endif
- class _Tp>
+ class _Tp,
+ enable_if_t<is_constructible_v<decay_t<_Tp>, _Tp>, int> = 0>
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr optional<decay_t<_Tp>> make_optional(_Tp&& __v) {
return optional<decay_t<_Tp>>(std::forward<_Tp>(__v));
}
diff --git a/libcxx/test/std/utilities/optional/optional.specalg/make_optional.pass.cpp b/libcxx/test/std/utilities/optional/optional.specalg/make_optional.pass.cpp
index c27645165d20e..0f358b53023dc 100644
--- a/libcxx/test/std/utilities/optional/optional.specalg/make_optional.pass.cpp
+++ b/libcxx/test/std/utilities/optional/optional.specalg/make_optional.pass.cpp
@@ -17,40 +17,79 @@
#include <memory>
#include <optional>
#include <string>
+#include <type_traits>
+#include <utility>
#include "test_macros.h"
-int main(int, char**)
-{
- {
- int arr[10];
- auto opt = std::make_optional(arr);
- ASSERT_SAME_TYPE(decltype(opt), std::optional<int*>);
- assert(*opt == arr);
- }
- {
- constexpr auto opt = std::make_optional(2);
- ASSERT_SAME_TYPE(decltype(opt), const std::optional<int>);
- static_assert(opt.value() == 2);
- }
- {
- auto opt = std::make_optional(2);
- ASSERT_SAME_TYPE(decltype(opt), std::optional<int>);
- assert(*opt == 2);
- }
- {
- const std::string s = "123";
- auto opt = std::make_optional(s);
- ASSERT_SAME_TYPE(decltype(opt), std::optional<std::string>);
- assert(*opt == "123");
- }
- {
- std::unique_ptr<int> s = std::make_unique<int>(3);
- auto opt = std::make_optional(std::move(s));
- ASSERT_SAME_TYPE(decltype(opt), std::optional<std::unique_ptr<int>>);
- assert(**opt == 3);
- assert(s == nullptr);
- }
+template <class T, class U>
+struct mandate_same {
+ ASSERT_SAME_TYPE(T, U);
+ static constexpr bool value = true;
+};
+
+template <class T, class = void>
+constexpr bool can_make_optional_implicit = false;
+template <class T>
+constexpr bool can_make_optional_implicit<T, std::void_t<decltype(std::make_optional(std::declval<T>()))>> =
+ mandate_same<decltype(std::make_optional(std::declval<T>())), std::optional<std::decay_t<T>>>::value;
+
+static_assert(can_make_optional_implicit<int>);
+static_assert(can_make_optional_implicit<const int>);
+static_assert(can_make_optional_implicit<int&>);
+static_assert(can_make_optional_implicit<const int&>);
+
+static_assert(can_make_optional_implicit<std::unique_ptr<int>>);
+static_assert(!can_make_optional_implicit<const std::unique_ptr<int>>);
+static_assert(!can_make_optional_implicit<std::unique_ptr<int>&>);
+static_assert(!can_make_optional_implicit<const std::unique_ptr<int>&>);
+
+static_assert(can_make_optional_implicit<int[42]>);
+static_assert(can_make_optional_implicit<const int (&)[42]>);
+
+constexpr bool test() {
+ {
+ int arr[10]{};
+ auto opt = std::make_optional(arr);
+ ASSERT_SAME_TYPE(decltype(opt), std::optional<int*>);
+ assert(*opt == arr);
+ }
+ {
+ constexpr auto opt = std::make_optional(2);
+ ASSERT_SAME_TYPE(decltype(opt), const std::optional<int>);
+ static_assert(opt.value() == 2);
+ }
+ {
+ auto opt = std::make_optional(2);
+ ASSERT_SAME_TYPE(decltype(opt), std::optional<int>);
+ assert(*opt == 2);
+ }
+
+ constexpr auto test_string = [] {
+ const std::string s = "123";
+ auto opt = std::make_optional(s);
+ ASSERT_SAME_TYPE(decltype(opt), std::optional<std::string>);
+ assert(*opt == "123");
+ };
+ if (TEST_STD_AT_LEAST_20_OR_RUNTIME_EVALUATED)
+ test_string();
+
+ constexpr auto test_unique_ptr = [] {
+ std::unique_ptr<int> s = std::make_unique<int>(3);
+ auto opt = std::make_optional(std::move(s));
+ ASSERT_SAME_TYPE(decltype(opt), std::optional<std::unique_ptr<int>>);
+ assert(**opt == 3);
+ assert(s == nullptr);
+ };
+ if (TEST_STD_AT_LEAST_23_OR_RUNTIME_EVALUATED)
+ test_unique_ptr();
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
return 0;
}
More information about the libcxx-commits
mailing list