[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