[libcxx-commits] [libcxx] beecf2c - [libc++] Fix missing declarations of uses_allocator_construction_args (#67044)

via libcxx-commits libcxx-commits at lists.llvm.org
Thu Aug 1 05:54:46 PDT 2024


Author: Shivam
Date: 2024-08-01T08:54:43-04:00
New Revision: beecf2c6052485d99c6db86422aebdb433f98b5a

URL: https://github.com/llvm/llvm-project/commit/beecf2c6052485d99c6db86422aebdb433f98b5a
DIFF: https://github.com/llvm/llvm-project/commit/beecf2c6052485d99c6db86422aebdb433f98b5a.diff

LOG: [libc++] Fix missing declarations of uses_allocator_construction_args (#67044)

We were not declaring `__uses_allocator_construction_args` helper 
functions, leading to several valid uses failing to compile. This
patch solves the problem by moving these helper functions into a
struct, which also reduces the amount of redundant SFINAE we need
to perform since most overloads are checking for a cv-qualfied pair.

Fixes #66714

Co-authored-by: Louis Dionne <ldionne.2 at gmail.com>

Added: 
    

Modified: 
    libcxx/include/__memory/uses_allocator_construction.h
    libcxx/test/std/utilities/memory/allocator.uses/allocator.uses.construction/uses_allocator_construction_args.pass.cpp

Removed: 
    


################################################################################
diff  --git a/libcxx/include/__memory/uses_allocator_construction.h b/libcxx/include/__memory/uses_allocator_construction.h
index 5e5819d4c281e..955879ffc5845 100644
--- a/libcxx/include/__memory/uses_allocator_construction.h
+++ b/libcxx/include/__memory/uses_allocator_construction.h
@@ -40,104 +40,8 @@ inline constexpr bool __is_std_pair<pair<_Type1, _Type2>> = true;
 template <class _Tp>
 inline constexpr bool __is_cv_std_pair = __is_std_pair<remove_cv_t<_Tp>>;
 
-template <class _Type, class _Alloc, class... _Args, __enable_if_t<!__is_cv_std_pair<_Type>, int> = 0>
-_LIBCPP_HIDE_FROM_ABI constexpr auto
-__uses_allocator_construction_args(const _Alloc& __alloc, _Args&&... __args) noexcept {
-  if constexpr (!uses_allocator_v<remove_cv_t<_Type>, _Alloc> && is_constructible_v<_Type, _Args...>) {
-    return std::forward_as_tuple(std::forward<_Args>(__args)...);
-  } else if constexpr (uses_allocator_v<remove_cv_t<_Type>, _Alloc> &&
-                       is_constructible_v<_Type, allocator_arg_t, const _Alloc&, _Args...>) {
-    return tuple<allocator_arg_t, const _Alloc&, _Args&&...>(allocator_arg, __alloc, std::forward<_Args>(__args)...);
-  } else if constexpr (uses_allocator_v<remove_cv_t<_Type>, _Alloc> &&
-                       is_constructible_v<_Type, _Args..., const _Alloc&>) {
-    return std::forward_as_tuple(std::forward<_Args>(__args)..., __alloc);
-  } else {
-    static_assert(
-        sizeof(_Type) + 1 == 0, "If uses_allocator_v<Type> is true, the type has to be allocator-constructible");
-  }
-}
-
-template <class _Pair, class _Alloc, class _Tuple1, class _Tuple2, __enable_if_t<__is_cv_std_pair<_Pair>, int> = 0>
-_LIBCPP_HIDE_FROM_ABI constexpr auto __uses_allocator_construction_args(
-    const _Alloc& __alloc, piecewise_construct_t, _Tuple1&& __x, _Tuple2&& __y) noexcept {
-  return std::make_tuple(
-      piecewise_construct,
-      std::apply(
-          [&__alloc](auto&&... __args1) {
-            return std::__uses_allocator_construction_args<typename _Pair::first_type>(
-                __alloc, std::forward<decltype(__args1)>(__args1)...);
-          },
-          std::forward<_Tuple1>(__x)),
-      std::apply(
-          [&__alloc](auto&&... __args2) {
-            return std::__uses_allocator_construction_args<typename _Pair::second_type>(
-                __alloc, std::forward<decltype(__args2)>(__args2)...);
-          },
-          std::forward<_Tuple2>(__y)));
-}
-
-template <class _Pair, class _Alloc, __enable_if_t<__is_cv_std_pair<_Pair>, int> = 0>
-_LIBCPP_HIDE_FROM_ABI constexpr auto __uses_allocator_construction_args(const _Alloc& __alloc) noexcept {
-  return std::__uses_allocator_construction_args<_Pair>(__alloc, piecewise_construct, tuple<>{}, tuple<>{});
-}
-
-template <class _Pair, class _Alloc, class _Up, class _Vp, __enable_if_t<__is_cv_std_pair<_Pair>, int> = 0>
-_LIBCPP_HIDE_FROM_ABI constexpr auto
-__uses_allocator_construction_args(const _Alloc& __alloc, _Up&& __u, _Vp&& __v) noexcept {
-  return std::__uses_allocator_construction_args<_Pair>(
-      __alloc,
-      piecewise_construct,
-      std::forward_as_tuple(std::forward<_Up>(__u)),
-      std::forward_as_tuple(std::forward<_Vp>(__v)));
-}
-
-#  if _LIBCPP_STD_VER >= 23
-template <class _Pair, class _Alloc, class _Up, class _Vp, __enable_if_t<__is_cv_std_pair<_Pair>, int> = 0>
-_LIBCPP_HIDE_FROM_ABI constexpr auto
-__uses_allocator_construction_args(const _Alloc& __alloc, pair<_Up, _Vp>& __pair) noexcept {
-  return std::__uses_allocator_construction_args<_Pair>(
-      __alloc, piecewise_construct, std::forward_as_tuple(__pair.first), std::forward_as_tuple(__pair.second));
-}
-#  endif
-
-template <class _Pair, class _Alloc, class _Up, class _Vp, __enable_if_t<__is_cv_std_pair<_Pair>, int> = 0>
-_LIBCPP_HIDE_FROM_ABI constexpr auto
-__uses_allocator_construction_args(const _Alloc& __alloc, const pair<_Up, _Vp>& __pair) noexcept {
-  return std::__uses_allocator_construction_args<_Pair>(
-      __alloc, piecewise_construct, std::forward_as_tuple(__pair.first), std::forward_as_tuple(__pair.second));
-}
-
-template <class _Pair, class _Alloc, class _Up, class _Vp, __enable_if_t<__is_cv_std_pair<_Pair>, int> = 0>
-_LIBCPP_HIDE_FROM_ABI constexpr auto
-__uses_allocator_construction_args(const _Alloc& __alloc, pair<_Up, _Vp>&& __pair) noexcept {
-  return std::__uses_allocator_construction_args<_Pair>(
-      __alloc,
-      piecewise_construct,
-      std::forward_as_tuple(std::get<0>(std::move(__pair))),
-      std::forward_as_tuple(std::get<1>(std::move(__pair))));
-}
-
-#  if _LIBCPP_STD_VER >= 23
-template <class _Pair, class _Alloc, class _Up, class _Vp, __enable_if_t<__is_cv_std_pair<_Pair>, int> = 0>
-_LIBCPP_HIDE_FROM_ABI constexpr auto
-__uses_allocator_construction_args(const _Alloc& __alloc, const pair<_Up, _Vp>&& __pair) noexcept {
-  return std::__uses_allocator_construction_args<_Pair>(
-      __alloc,
-      piecewise_construct,
-      std::forward_as_tuple(std::get<0>(std::move(__pair))),
-      std::forward_as_tuple(std::get<1>(std::move(__pair))));
-}
-
-template <class _Pair, class _Alloc, __pair_like_no_subrange _PairLike, __enable_if_t<__is_cv_std_pair<_Pair>, int> = 0>
-_LIBCPP_HIDE_FROM_ABI constexpr auto
-__uses_allocator_construction_args(const _Alloc& __alloc, _PairLike&& __p) noexcept {
-  return std::__uses_allocator_construction_args<_Pair>(
-      __alloc,
-      piecewise_construct,
-      std::forward_as_tuple(std::get<0>(std::forward<_PairLike>(__p))),
-      std::forward_as_tuple(std::get<1>(std::forward<_PairLike>(__p))));
-}
-#  endif
+template <class _Tp, class = void>
+struct __uses_allocator_construction_args;
 
 namespace __uses_allocator_detail {
 
@@ -165,46 +69,135 @@ inline constexpr bool __uses_allocator_constraints = __is_cv_std_pair<_Tp> && !_
 
 } // namespace __uses_allocator_detail
 
-template < class _Pair,
-           class _Alloc,
-           class _Type,
-           __enable_if_t<__uses_allocator_detail::__uses_allocator_constraints<_Pair, _Type>, int> = 0>
-_LIBCPP_HIDE_FROM_ABI constexpr auto
-__uses_allocator_construction_args(const _Alloc& __alloc, _Type&& __value) noexcept;
-
 template <class _Type, class _Alloc, class... _Args>
 _LIBCPP_HIDE_FROM_ABI constexpr _Type __make_obj_using_allocator(const _Alloc& __alloc, _Args&&... __args);
 
-template < class _Pair,
-           class _Alloc,
-           class _Type,
-           __enable_if_t< __uses_allocator_detail::__uses_allocator_constraints<_Pair, _Type>, int>>
-_LIBCPP_HIDE_FROM_ABI constexpr auto
-__uses_allocator_construction_args(const _Alloc& __alloc, _Type&& __value) noexcept {
-  struct __pair_constructor {
-    using _PairMutable = remove_cv_t<_Pair>;
+template <class _Pair>
+struct __uses_allocator_construction_args<_Pair, __enable_if_t<__is_cv_std_pair<_Pair>>> {
+  template <class _Alloc, class _Tuple1, class _Tuple2>
+  static _LIBCPP_HIDE_FROM_ABI constexpr auto
+  __apply(const _Alloc& __alloc, piecewise_construct_t, _Tuple1&& __x, _Tuple2&& __y) noexcept {
+    return std::make_tuple(
+        piecewise_construct,
+        std::apply(
+            [&__alloc](auto&&... __args1) {
+              return __uses_allocator_construction_args<typename _Pair::first_type>::__apply(
+                  __alloc, std::forward<decltype(__args1)>(__args1)...);
+            },
+            std::forward<_Tuple1>(__x)),
+        std::apply(
+            [&__alloc](auto&&... __args2) {
+              return __uses_allocator_construction_args<typename _Pair::second_type>::__apply(
+                  __alloc, std::forward<decltype(__args2)>(__args2)...);
+            },
+            std::forward<_Tuple2>(__y)));
+  }
 
-    _LIBCPP_HIDDEN constexpr auto __do_construct(const _PairMutable& __pair) const {
-      return std::__make_obj_using_allocator<_PairMutable>(__alloc_, __pair);
-    }
+  template <class _Alloc>
+  static _LIBCPP_HIDE_FROM_ABI constexpr auto __apply(const _Alloc& __alloc) noexcept {
+    return __uses_allocator_construction_args<_Pair>::__apply(__alloc, piecewise_construct, tuple<>{}, tuple<>{});
+  }
 
-    _LIBCPP_HIDDEN constexpr auto __do_construct(_PairMutable&& __pair) const {
-      return std::__make_obj_using_allocator<_PairMutable>(__alloc_, std::move(__pair));
-    }
+  template <class _Alloc, class _Up, class _Vp>
+  static _LIBCPP_HIDE_FROM_ABI constexpr auto __apply(const _Alloc& __alloc, _Up&& __u, _Vp&& __v) noexcept {
+    return __uses_allocator_construction_args<_Pair>::__apply(
+        __alloc,
+        piecewise_construct,
+        std::forward_as_tuple(std::forward<_Up>(__u)),
+        std::forward_as_tuple(std::forward<_Vp>(__v)));
+  }
 
-    const _Alloc& __alloc_;
-    _Type& __value_;
+#  if _LIBCPP_STD_VER >= 23
+  template <class _Alloc, class _Up, class _Vp>
+  static _LIBCPP_HIDE_FROM_ABI constexpr auto __apply(const _Alloc& __alloc, pair<_Up, _Vp>& __pair) noexcept {
+    return __uses_allocator_construction_args<_Pair>::__apply(
+        __alloc, piecewise_construct, std::forward_as_tuple(__pair.first), std::forward_as_tuple(__pair.second));
+  }
+#  endif
 
-    _LIBCPP_HIDDEN constexpr operator _PairMutable() const { return __do_construct(std::forward<_Type>(__value_)); }
-  };
+  template <class _Alloc, class _Up, class _Vp>
+  static _LIBCPP_HIDE_FROM_ABI constexpr auto __apply(const _Alloc& __alloc, const pair<_Up, _Vp>& __pair) noexcept {
+    return __uses_allocator_construction_args<_Pair>::__apply(
+        __alloc, piecewise_construct, std::forward_as_tuple(__pair.first), std::forward_as_tuple(__pair.second));
+  }
 
-  return std::make_tuple(__pair_constructor{__alloc, __value});
-}
+  template <class _Alloc, class _Up, class _Vp>
+  static _LIBCPP_HIDE_FROM_ABI constexpr auto __apply(const _Alloc& __alloc, pair<_Up, _Vp>&& __pair) noexcept {
+    return __uses_allocator_construction_args<_Pair>::__apply(
+        __alloc,
+        piecewise_construct,
+        std::forward_as_tuple(std::get<0>(std::move(__pair))),
+        std::forward_as_tuple(std::get<1>(std::move(__pair))));
+  }
+
+#  if _LIBCPP_STD_VER >= 23
+  template <class _Alloc, class _Up, class _Vp>
+  static _LIBCPP_HIDE_FROM_ABI constexpr auto __apply(const _Alloc& __alloc, const pair<_Up, _Vp>&& __pair) noexcept {
+    return __uses_allocator_construction_args<_Pair>::__apply(
+        __alloc,
+        piecewise_construct,
+        std::forward_as_tuple(std::get<0>(std::move(__pair))),
+        std::forward_as_tuple(std::get<1>(std::move(__pair))));
+  }
+
+  template < class _Alloc, __pair_like_no_subrange _PairLike>
+  static _LIBCPP_HIDE_FROM_ABI constexpr auto __apply(const _Alloc& __alloc, _PairLike&& __p) noexcept {
+    return __uses_allocator_construction_args<_Pair>::__apply(
+        __alloc,
+        piecewise_construct,
+        std::forward_as_tuple(std::get<0>(std::forward<_PairLike>(__p))),
+        std::forward_as_tuple(std::get<1>(std::forward<_PairLike>(__p))));
+  }
+#  endif
+
+  template <class _Alloc,
+            class _Type,
+            __enable_if_t<__uses_allocator_detail::__uses_allocator_constraints<_Pair, _Type>, int> = 0>
+  static _LIBCPP_HIDE_FROM_ABI constexpr auto __apply(const _Alloc& __alloc, _Type&& __value) noexcept {
+    struct __pair_constructor {
+      using _PairMutable = remove_cv_t<_Pair>;
+
+      _LIBCPP_HIDDEN constexpr auto __do_construct(const _PairMutable& __pair) const {
+        return std::__make_obj_using_allocator<_PairMutable>(__alloc_, __pair);
+      }
+
+      _LIBCPP_HIDDEN constexpr auto __do_construct(_PairMutable&& __pair) const {
+        return std::__make_obj_using_allocator<_PairMutable>(__alloc_, std::move(__pair));
+      }
+
+      const _Alloc& __alloc_;
+      _Type& __value_;
+
+      _LIBCPP_HIDDEN constexpr operator _PairMutable() const { return __do_construct(std::forward<_Type>(__value_)); }
+    };
+
+    return std::make_tuple(__pair_constructor{__alloc, __value});
+  }
+};
+
+template <class _Type>
+struct __uses_allocator_construction_args<_Type, __enable_if_t<!__is_cv_std_pair<_Type>>> {
+  template <class _Alloc, class... _Args>
+  static _LIBCPP_HIDE_FROM_ABI constexpr auto __apply(const _Alloc& __alloc, _Args&&... __args) noexcept {
+    if constexpr (!uses_allocator_v<remove_cv_t<_Type>, _Alloc> && is_constructible_v<_Type, _Args...>) {
+      return std::forward_as_tuple(std::forward<_Args>(__args)...);
+    } else if constexpr (uses_allocator_v<remove_cv_t<_Type>, _Alloc> &&
+                         is_constructible_v<_Type, allocator_arg_t, const _Alloc&, _Args...>) {
+      return tuple<allocator_arg_t, const _Alloc&, _Args&&...>(allocator_arg, __alloc, std::forward<_Args>(__args)...);
+    } else if constexpr (uses_allocator_v<remove_cv_t<_Type>, _Alloc> &&
+                         is_constructible_v<_Type, _Args..., const _Alloc&>) {
+      return std::forward_as_tuple(std::forward<_Args>(__args)..., __alloc);
+    } else {
+      static_assert(
+          sizeof(_Type) + 1 == 0, "If uses_allocator_v<Type> is true, the type has to be allocator-constructible");
+    }
+  }
+};
 
 template <class _Type, class _Alloc, class... _Args>
 _LIBCPP_HIDE_FROM_ABI constexpr _Type __make_obj_using_allocator(const _Alloc& __alloc, _Args&&... __args) {
   return std::make_from_tuple<_Type>(
-      std::__uses_allocator_construction_args<_Type>(__alloc, std::forward<_Args>(__args)...));
+      __uses_allocator_construction_args<_Type>::__apply(__alloc, std::forward<_Args>(__args)...));
 }
 
 template <class _Type, class _Alloc, class... _Args>
@@ -212,7 +205,7 @@ _LIBCPP_HIDE_FROM_ABI constexpr _Type*
 __uninitialized_construct_using_allocator(_Type* __ptr, const _Alloc& __alloc, _Args&&... __args) {
   return std::apply(
       [&__ptr](auto&&... __xs) { return std::__construct_at(__ptr, std::forward<decltype(__xs)>(__xs)...); },
-      std::__uses_allocator_construction_args<_Type>(__alloc, std::forward<_Args>(__args)...));
+      __uses_allocator_construction_args<_Type>::__apply(__alloc, std::forward<_Args>(__args)...));
 }
 
 #endif // _LIBCPP_STD_VER >= 17
@@ -221,8 +214,8 @@ __uninitialized_construct_using_allocator(_Type* __ptr, const _Alloc& __alloc, _
 
 template <class _Type, class _Alloc, class... _Args>
 _LIBCPP_HIDE_FROM_ABI constexpr auto uses_allocator_construction_args(const _Alloc& __alloc, _Args&&... __args) noexcept
-    -> decltype(std::__uses_allocator_construction_args<_Type>(__alloc, std::forward<_Args>(__args)...)) {
-  return /*--*/ std::__uses_allocator_construction_args<_Type>(__alloc, std::forward<_Args>(__args)...);
+    -> decltype(__uses_allocator_construction_args<_Type>::__apply(__alloc, std::forward<_Args>(__args)...)) {
+  return /*--*/ __uses_allocator_construction_args<_Type>::__apply(__alloc, std::forward<_Args>(__args)...);
 }
 
 template <class _Type, class _Alloc, class... _Args>

diff  --git a/libcxx/test/std/utilities/memory/allocator.uses/allocator.uses.construction/uses_allocator_construction_args.pass.cpp b/libcxx/test/std/utilities/memory/allocator.uses/allocator.uses.construction/uses_allocator_construction_args.pass.cpp
index ab3c039497dd9..235a93987fe48 100644
--- a/libcxx/test/std/utilities/memory/allocator.uses/allocator.uses.construction/uses_allocator_construction_args.pass.cpp
+++ b/libcxx/test/std/utilities/memory/allocator.uses/allocator.uses.construction/uses_allocator_construction_args.pass.cpp
@@ -121,6 +121,63 @@ constexpr void testOne() {
     assert(std::get<2>(std::get<1>(ret)) == 3);
     assert(std::get<0>(std::get<2>(ret)) == 4);
   }
+  {
+    // Tests for ensuring forward declarations of uses_allocator_construction_args
+    // See https://github.com/llvm/llvm-project/issues/66714.
+    {
+      using NestedPairType = std::pair<int, std::pair<int, UsesAllocArgT>>;
+      std::same_as<std::tuple<
+          std::piecewise_construct_t,
+          std::tuple<>,
+          std::tuple<std::piecewise_construct_t, std::tuple<>, std::tuple<std::allocator_arg_t, const Alloc&>>>> auto
+          ret = test_uses_allocator_construction_args<NestedPairType>(a);
+      (void)ret;
+    }
+    {
+      using NestedPairType = std::pair<int, std::pair<UsesAllocArgT, int>>;
+      std::same_as<std::tuple<
+          std::piecewise_construct_t,
+          std::tuple<>,
+          std::tuple<std::piecewise_construct_t, std::tuple<std::allocator_arg_t, const Alloc&>, std::tuple<>>>> auto
+          ret = test_uses_allocator_construction_args<NestedPairType>(a);
+      (void)ret;
+    }
+    {
+      using PairType = std::pair<int, int>;
+      int up         = 1;
+      int vp         = 2;
+
+      std::same_as<std::tuple<std::piecewise_construct_t, std::tuple<int&&>, std::tuple<int&&>>> auto ret =
+          test_uses_allocator_construction_args<PairType>(a, std::move(up), std::move(vp));
+      (void)ret;
+    }
+    {
+      using PairType = const std::pair<int, int>;
+      PairType p(1, 2);
+
+      std::same_as<std::tuple<std::piecewise_construct_t, std::tuple<const int&>, std::tuple<const int&>>> auto ret =
+          test_uses_allocator_construction_args<PairType>(a, p);
+      (void)ret;
+    }
+    {
+      using PairType = std::pair<int, int>;
+      PairType p(1, 2);
+
+      std::same_as<std::tuple<std::piecewise_construct_t, std::tuple<int&&>, std::tuple<int&&>>> auto ret =
+          test_uses_allocator_construction_args<PairType>(a, std::move(p));
+      (void)ret;
+    }
+#if TEST_STD_VER >= 23
+    {
+      using PairType = const std::pair<int, int>;
+      PairType p(1, 2);
+
+      std::same_as<std::tuple<std::piecewise_construct_t, std::tuple<const int&&>, std::tuple<const int&&>>> auto ret =
+          test_uses_allocator_construction_args<PairType>(a, std::move(p));
+      (void)ret;
+    }
+#endif
+  }
 #if TEST_STD_VER >= 23
   {
     std::pair p{3, 4};


        


More information about the libcxx-commits mailing list