[libcxx-commits] [libcxx] [libc++] Complete overload removal in P3016R6 (PR #216932)

A. Jiang via libcxx-commits libcxx-commits at lists.llvm.org
Tue Aug 18 00:08:16 PDT 2026


https://github.com/frederick-vs-ja created https://github.com/llvm/llvm-project/pull/216932

P3016R6 also removed overloads of `std::data` and `std::empty` for `std::initializer_list`, but 8248eef4bea83086c4487215a465771f79e8759b missed these removals.

Note that the removal of that `std::empty` overload is almost NFC, as the overload for `const` array will be selected instead for `{vals...}`. Perhaps the removal is observable only when used with a user-defined overload.

The removal for `std::data` overload unconditionally makes `std::data({vals...})` ill-formed (which is good). To avoid potential IFNDR-ness, this PR tests unconventional `std::data<T>({vals...})` instead.

Drive-by changes: Sort includes and remove meaningless guards in touched test files.

>From f0e69033ebec55adeeee9fcba99b3930a3d17a94 Mon Sep 17 00:00:00 2001
From: "A. Jiang" <de34 at live.cn>
Date: Tue, 18 Aug 2026 15:06:16 +0800
Subject: [PATCH] [libc++] Complete overload removal in P3016R6

P3016R6 also removed overloads of `std::data` and `std::empty` for
`std::initializer_list`, but 8248eef4bea83086c4487215a465771f79e8759b
missed these removals.

Note that the removal of that `std::empty` overload is almost NFC, as
the overload for `const` array will be selected instead for `{vals...}`.
Perhaps the removal is observable only when used with a user-defined
overload.

The removal for `std::data` overload unconditionally makes
`std::data({vals...})` ill-formed (which is good). To avoid potential
IFNDR-ness, this PR tests unconventional `std::data<T>({vals...})`
instead.

Drive-by changes: Sort includes and remove meaningless guards in touched
test files.
---
 libcxx/include/__iterator/data.h              |  7 +---
 libcxx/include/__iterator/empty.h             |  7 +---
 .../iterator.container/data.pass.cpp          | 30 ++++++++++-------
 .../iterator.container/empty.pass.cpp         | 33 ++++++++++++-------
 4 files changed, 42 insertions(+), 35 deletions(-)

diff --git a/libcxx/include/__iterator/data.h b/libcxx/include/__iterator/data.h
index 7efa57e1a22a7..de5bba6ca2b45 100644
--- a/libcxx/include/__iterator/data.h
+++ b/libcxx/include/__iterator/data.h
@@ -11,7 +11,7 @@
 #define _LIBCPP___ITERATOR_DATA_H
 
 #include <__config>
-#include <initializer_list>
+#include <__cstddef/size_t.h>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
@@ -38,11 +38,6 @@ template <class _Tp, size_t _Sz>
   return __array;
 }
 
-template <class _Ep>
-[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const _Ep* data(initializer_list<_Ep> __il) noexcept {
-  return __il.begin();
-}
-
 _LIBCPP_END_NAMESPACE_STD
 
 #endif // _LIBCPP_STD_VER >= 17
diff --git a/libcxx/include/__iterator/empty.h b/libcxx/include/__iterator/empty.h
index b763048f547e5..7b8ffce21f757 100644
--- a/libcxx/include/__iterator/empty.h
+++ b/libcxx/include/__iterator/empty.h
@@ -11,7 +11,7 @@
 #define _LIBCPP___ITERATOR_EMPTY_H
 
 #include <__config>
-#include <initializer_list>
+#include <__cstddef/size_t.h>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
@@ -32,11 +32,6 @@ template <class _Tp, size_t _Sz>
   return false;
 }
 
-template <class _Ep>
-[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool empty(initializer_list<_Ep> __il) noexcept {
-  return __il.size() == 0;
-}
-
 _LIBCPP_END_NAMESPACE_STD
 
 #endif // _LIBCPP_STD_VER >= 17
diff --git a/libcxx/test/std/iterators/iterator.container/data.pass.cpp b/libcxx/test/std/iterators/iterator.container/data.pass.cpp
index b25587163f3c0..2aca37f6e3751 100644
--- a/libcxx/test/std/iterators/iterator.container/data.pass.cpp
+++ b/libcxx/test/std/iterators/iterator.container/data.pass.cpp
@@ -13,18 +13,16 @@
 // template <class C> constexpr auto data(const C& c) -> decltype(c.data());         // C++17
 // template <class T, size_t N> constexpr T* data(T (&array)[N]) noexcept;           // C++17
 
-#include <iterator>
-#include <cassert>
-#include <vector>
 #include <array>
+#include <cassert>
+#include <iterator>
 #include <initializer_list>
+#include <string_view>
+#include <type_traits>
+#include <vector>
 
 #include "test_macros.h"
 
-#if TEST_STD_VER > 14
-#include <string_view>
-#endif
-
 template<typename C>
 void test_const_container( const C& c )
 {
@@ -60,6 +58,18 @@ void test_const_array( const T (&array)[Sz] )
     assert ( std::data(array) == &array[0]);
 }
 
+// Verify that the std::data overload for std::initializer_list is removed by P3016R6.
+template <class T, class = void>
+constexpr bool can_std_data_with_int_list = false;
+template <class T>
+constexpr bool can_std_data_with_int_list<T, std::void_t<decltype(std::data<T>({1, 2, 3}))>> = true;
+
+static_assert(!can_std_data_with_int_list<int>);
+// When C is a range type convertible from {1, 2, 3}, the overload for const C& is selected.
+static_assert(can_std_data_with_int_list<std::vector<int>>);
+static_assert(can_std_data_with_int_list<std::array<int, 3>>);
+static_assert(can_std_data_with_int_list<std::initializer_list<int>>);
+
 int main(int, char**)
 {
     std::vector<int> v; v.push_back(1);
@@ -74,11 +84,9 @@ int main(int, char**)
     test_const_container ( a );
     test_const_container ( il );
 
-#if TEST_STD_VER > 14
     std::string_view sv{"ABC"};
-    test_container ( sv );
-    test_const_container ( sv );
-#endif
+    test_container(sv);
+    test_const_container(sv);
 
     static constexpr int arrA [] { 1, 2, 3 };
     test_const_array ( arrA );
diff --git a/libcxx/test/std/iterators/iterator.container/empty.pass.cpp b/libcxx/test/std/iterators/iterator.container/empty.pass.cpp
index 2593ba3b0e56e..1cf343dafcac4 100644
--- a/libcxx/test/std/iterators/iterator.container/empty.pass.cpp
+++ b/libcxx/test/std/iterators/iterator.container/empty.pass.cpp
@@ -12,19 +12,17 @@
 // template <class C> constexpr auto empty(const C& c) -> decltype(c.empty());       // C++17
 // template <class T, size_t N> constexpr bool empty(const T (&array)[N]) noexcept;  // C++17
 
-#include <iterator>
-#include <cassert>
-#include <vector>
 #include <array>
-#include <list>
+#include <cassert>
 #include <initializer_list>
+#include <iterator>
+#include <list>
+#include <string_view>
+#include <type_traits>
+#include <vector>
 
 #include "test_macros.h"
 
-#if TEST_STD_VER > 14
-#include <string_view>
-#endif
-
 template<typename C>
 void test_const_container( const C& c )
 {
@@ -59,6 +57,11 @@ void test_const_array( const T (&array)[Sz] )
     assert (!std::empty(array));
 }
 
+namespace p3016r6 {
+template <class T>
+void empty(std::initializer_list<T>);
+}
+
 int main(int, char**)
 {
     std::vector<int> v; v.push_back(1);
@@ -76,14 +79,20 @@ int main(int, char**)
     test_const_container ( a );
     test_const_container ( il );
 
-#if TEST_STD_VER > 14
     std::string_view sv{"ABC"};
-    test_container ( sv );
-    test_const_container ( sv );
-#endif
+    test_container(sv);
+    test_const_container(sv);
 
     static constexpr int arrA [] { 1, 2, 3 };
     test_const_array ( arrA );
 
+    {
+      // Verify that the std::empty overload for std::initializer_list is absent (removed by P3016R6).
+      // The behavior of std::empty({vals...}) is unchanged because the overload for const T(&)[N] is used.
+      using p3016r6::empty;
+      using std::empty;
+      static_assert(std::is_same_v<decltype(empty({1, 2, 3})), void>);
+    }
+
   return 0;
 }



More information about the libcxx-commits mailing list