[libcxx-commits] [libcxx] [libc++] Fix std::variant/std::invoke too eager instantiation (PR #151028)

Nikolas Klauser via libcxx-commits libcxx-commits at lists.llvm.org
Thu Jul 31 01:42:10 PDT 2025


https://github.com/philnik777 updated https://github.com/llvm/llvm-project/pull/151028

>From 10260aa4b7bc7e49e35cc5f9f313f8140e46877b Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Mon, 28 Jul 2025 21:35:47 +0200
Subject: [PATCH] [libc++] Fix std::variant/std::invoke too eager instantiation

---
 libcxx/include/variant                        | 22 +++++++++++++------
 .../variant.variant/variant.ctor/T.pass.cpp   | 16 ++++++++++++++
 2 files changed, 31 insertions(+), 7 deletions(-)

diff --git a/libcxx/include/variant b/libcxx/include/variant
index 9beef146f203c..6f9f86929ef65 100644
--- a/libcxx/include/variant
+++ b/libcxx/include/variant
@@ -1182,13 +1182,21 @@ public:
   _LIBCPP_HIDE_FROM_ABI constexpr variant(const variant&) = default;
   _LIBCPP_HIDE_FROM_ABI constexpr variant(variant&&)      = default;
 
-  template < class _Arg,
-             enable_if_t<!is_same_v<__remove_cvref_t<_Arg>, variant>, int>        = 0,
-             enable_if_t<!__is_inplace_type<__remove_cvref_t<_Arg>>::value, int>  = 0,
-             enable_if_t<!__is_inplace_index<__remove_cvref_t<_Arg>>::value, int> = 0,
-             class _Tp  = __variant_detail::__best_match_t<_Arg, _Types...>,
-             size_t _Ip = __find_detail::__find_unambiguous_index_sfinae<_Tp, _Types...>::value,
-             enable_if_t<is_constructible_v<_Tp, _Arg>, int> = 0>
+  template <class _Arg,
+            bool = !is_same_v<__remove_cvref_t<_Arg>, variant> && !__is_inplace_type<__remove_cvref_t<_Arg>>::value &&
+                   !__is_inplace_index<__remove_cvref_t<_Arg>>::value,
+            class = void>
+  struct __arg_overload_type {};
+
+  template <class _Arg>
+  struct __arg_overload_type<_Arg, true, __void_t<__variant_detail::__best_match_t<_Arg, _Types...>>> {
+    using type _LIBCPP_NODEBUG = __variant_detail::__best_match_t<_Arg, _Types...>;
+  };
+
+  template <class _Arg,
+            class _Tp  = typename __arg_overload_type<_Arg>::type,
+            size_t _Ip = __find_detail::__find_unambiguous_index_sfinae<_Tp, _Types...>::value,
+            enable_if_t<is_constructible_v<_Tp, _Arg>, int> = 0>
   _LIBCPP_HIDE_FROM_ABI constexpr variant(_Arg&& __arg) noexcept(is_nothrow_constructible_v<_Tp, _Arg>)
       : __impl_(in_place_index<_Ip>, std::forward<_Arg>(__arg)) {}
 
diff --git a/libcxx/test/std/utilities/variant/variant.variant/variant.ctor/T.pass.cpp b/libcxx/test/std/utilities/variant/variant.variant/variant.ctor/T.pass.cpp
index 142da1d820d9a..3c5cb3ca34971 100644
--- a/libcxx/test/std/utilities/variant/variant.variant/variant.ctor/T.pass.cpp
+++ b/libcxx/test/std/utilities/variant/variant.variant/variant.ctor/T.pass.cpp
@@ -173,6 +173,11 @@ void test_vector_bool() {
   assert(std::get<0>(v) == true);
 }
 
+struct ConvertibleFromAny {
+  template <class V>
+  ConvertibleFromAny(V) {}
+};
+
 int main(int, char**) {
   test_T_ctor_basic();
   test_T_ctor_noexcept();
@@ -180,5 +185,16 @@ int main(int, char**) {
   test_no_narrowing_check_for_class_types();
   test_construction_with_repeated_types();
   test_vector_bool();
+
+  { // Check that the constraints are evaluated lazily
+    struct Matcher {
+      Matcher() {}
+      Matcher(std::variant<ConvertibleFromAny>) {}
+    };
+
+    Matcher vec;
+    [[maybe_unused]] Matcher m = std::move(vec);
+  }
+
   return 0;
 }



More information about the libcxx-commits mailing list