[libcxx-commits] [libcxx] 8507383 - [libc++] [ranges] ADL-proof the [range.access] CPOs.
Arthur O'Dwyer via libcxx-commits
libcxx-commits at lists.llvm.org
Tue Jan 4 14:17:54 PST 2022
Author: Arthur O'Dwyer
Date: 2022-01-04T17:15:42-05:00
New Revision: 8507383631f2ce2254e35bb81e03319ede056ed1
URL: https://github.com/llvm/llvm-project/commit/8507383631f2ce2254e35bb81e03319ede056ed1
DIFF: https://github.com/llvm/llvm-project/commit/8507383631f2ce2254e35bb81e03319ede056ed1.diff
LOG: [libc++] [ranges] ADL-proof the [range.access] CPOs.
For example, `std::ranges::range<Holder<Incomplete>*>` should be
well-formed false, not a hard error at compile time.
Differential Revision: https://reviews.llvm.org/D116239
Added:
Modified:
libcxx/include/__concepts/class_or_enum.h
libcxx/include/__ranges/access.h
libcxx/include/__ranges/empty.h
libcxx/include/__ranges/size.h
libcxx/test/std/ranges/range.access/begin.pass.cpp
libcxx/test/std/ranges/range.access/data.pass.cpp
libcxx/test/std/ranges/range.access/empty.pass.cpp
libcxx/test/std/ranges/range.access/end.pass.cpp
libcxx/test/std/ranges/range.access/size.pass.cpp
libcxx/test/std/ranges/range.access/ssize.pass.cpp
libcxx/test/std/ranges/range.req/range.range/range.compile.pass.cpp
Removed:
################################################################################
diff --git a/libcxx/include/__concepts/class_or_enum.h b/libcxx/include/__concepts/class_or_enum.h
index 43c7636d9c818..aa8606a219290 100644
--- a/libcxx/include/__concepts/class_or_enum.h
+++ b/libcxx/include/__concepts/class_or_enum.h
@@ -25,6 +25,10 @@ _LIBCPP_BEGIN_NAMESPACE_STD
template<class _Tp>
concept __class_or_enum = is_class_v<_Tp> || is_union_v<_Tp> || is_enum_v<_Tp>;
+// Work around Clang bug https://llvm.org/PR52970
+template<class _Tp>
+concept __workaround_52970 = is_class_v<__uncvref_t<_Tp>> || is_union_v<__uncvref_t<_Tp>>;
+
#endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_CONCEPTS)
_LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/include/__ranges/access.h b/libcxx/include/__ranges/access.h
index 4a1242130ac05..246f8b20caf43 100644
--- a/libcxx/include/__ranges/access.h
+++ b/libcxx/include/__ranges/access.h
@@ -9,6 +9,7 @@
#ifndef _LIBCPP___RANGES_ACCESS_H
#define _LIBCPP___RANGES_ACCESS_H
+#include <__concepts/class_or_enum.h>
#include <__config>
#include <__iterator/concepts.h>
#include <__iterator/readable_traits.h>
@@ -39,6 +40,7 @@ namespace __begin {
template <class _Tp>
concept __member_begin =
__can_borrow<_Tp> &&
+ __workaround_52970<_Tp> &&
requires(_Tp&& __t) {
{ _LIBCPP_AUTO_CAST(__t.begin()) } -> input_or_output_iterator;
};
@@ -102,6 +104,7 @@ namespace __end {
template <class _Tp>
concept __member_end =
__can_borrow<_Tp> &&
+ __workaround_52970<_Tp> &&
requires(_Tp&& __t) {
typename iterator_t<_Tp>;
{ _LIBCPP_AUTO_CAST(__t.end()) } -> sentinel_for<iterator_t<_Tp>>;
diff --git a/libcxx/include/__ranges/empty.h b/libcxx/include/__ranges/empty.h
index e8a8aabf4aed6..8da0b120f182c 100644
--- a/libcxx/include/__ranges/empty.h
+++ b/libcxx/include/__ranges/empty.h
@@ -9,6 +9,7 @@
#ifndef _LIBCPP___RANGES_EMPTY_H
#define _LIBCPP___RANGES_EMPTY_H
+#include <__concepts/class_or_enum.h>
#include <__config>
#include <__iterator/concepts.h>
#include <__ranges/access.h>
@@ -28,9 +29,11 @@ _LIBCPP_BEGIN_NAMESPACE_STD
namespace ranges {
namespace __empty {
template <class _Tp>
- concept __member_empty = requires(_Tp&& __t) {
- bool(__t.empty());
- };
+ concept __member_empty =
+ __workaround_52970<_Tp> &&
+ requires(_Tp&& __t) {
+ bool(__t.empty());
+ };
template<class _Tp>
concept __can_invoke_size =
diff --git a/libcxx/include/__ranges/size.h b/libcxx/include/__ranges/size.h
index fc6641cf4887b..f3de5a8b84102 100644
--- a/libcxx/include/__ranges/size.h
+++ b/libcxx/include/__ranges/size.h
@@ -9,6 +9,7 @@
#ifndef _LIBCPP___RANGES_SIZE_H
#define _LIBCPP___RANGES_SIZE_H
+#include <__concepts/class_or_enum.h>
#include <__config>
#include <__iterator/concepts.h>
#include <__iterator/iterator_traits.h>
@@ -41,9 +42,12 @@ namespace __size {
concept __size_enabled = !disable_sized_range<remove_cvref_t<_Tp>>;
template <class _Tp>
- concept __member_size = __size_enabled<_Tp> && requires(_Tp&& __t) {
- { _LIBCPP_AUTO_CAST(__t.size()) } -> __integer_like;
- };
+ concept __member_size =
+ __size_enabled<_Tp> &&
+ __workaround_52970<_Tp> &&
+ requires(_Tp&& __t) {
+ { _LIBCPP_AUTO_CAST(__t.size()) } -> __integer_like;
+ };
template <class _Tp>
concept __unqualified_size =
diff --git a/libcxx/test/std/ranges/range.access/begin.pass.cpp b/libcxx/test/std/ranges/range.access/begin.pass.cpp
index 1a6951967f88a..11170fa4f9943 100644
--- a/libcxx/test/std/ranges/range.access/begin.pass.cpp
+++ b/libcxx/test/std/ranges/range.access/begin.pass.cpp
@@ -303,6 +303,12 @@ struct BeginReturnsArrayRef {
static_assert(noexcept(std::ranges::begin(brar)));
static_assert(noexcept(std::ranges::cbegin(brar)));
+// Test ADL-proofing.
+struct Incomplete;
+template<class T> struct Holder { T t; };
+static_assert(!std::is_invocable_v<RangeBeginT, Holder<Incomplete>*>);
+static_assert(!std::is_invocable_v<RangeCBeginT, Holder<Incomplete>*>);
+
int main(int, char**) {
static_assert(testReturnTypes());
diff --git a/libcxx/test/std/ranges/range.access/data.pass.cpp b/libcxx/test/std/ranges/range.access/data.pass.cpp
index 40d2d3ab8eca5..6d0b718f6b040 100644
--- a/libcxx/test/std/ranges/range.access/data.pass.cpp
+++ b/libcxx/test/std/ranges/range.access/data.pass.cpp
@@ -176,6 +176,11 @@ constexpr bool testViaRangesBegin() {
return true;
}
+// Test ADL-proofing.
+struct Incomplete;
+template<class T> struct Holder { T t; };
+static_assert(!std::is_invocable_v<RangeDataT, Holder<Incomplete>*>);
+
struct RandomButNotContiguous {
random_access_iterator<int*> begin() const;
random_access_iterator<int*> end() const;
diff --git a/libcxx/test/std/ranges/range.access/empty.pass.cpp b/libcxx/test/std/ranges/range.access/empty.pass.cpp
index 18cdce02b5739..5724acc67deea 100644
--- a/libcxx/test/std/ranges/range.access/empty.pass.cpp
+++ b/libcxx/test/std/ranges/range.access/empty.pass.cpp
@@ -168,6 +168,11 @@ constexpr bool testBeginEqualsEnd() {
return true;
}
+// Test ADL-proofing.
+struct Incomplete;
+template<class T> struct Holder { T t; };
+static_assert(!std::is_invocable_v<RangeEmptyT, Holder<Incomplete>*>);
+
int main(int, char**) {
testEmptyMember();
static_assert(testEmptyMember());
diff --git a/libcxx/test/std/ranges/range.access/end.pass.cpp b/libcxx/test/std/ranges/range.access/end.pass.cpp
index 27eaf741a1131..4b1d4e3f488d0 100644
--- a/libcxx/test/std/ranges/range.access/end.pass.cpp
+++ b/libcxx/test/std/ranges/range.access/end.pass.cpp
@@ -350,6 +350,12 @@ struct EndReturnsArrayRef {
static_assert(noexcept(std::ranges::end(erar)));
static_assert(noexcept(std::ranges::cend(erar)));
+// Test ADL-proofing.
+struct Incomplete;
+template<class T> struct Holder { T t; };
+static_assert(!std::is_invocable_v<RangeEndT, Holder<Incomplete>*>);
+static_assert(!std::is_invocable_v<RangeCEndT, Holder<Incomplete>*>);
+
int main(int, char**) {
static_assert(testReturnTypes());
diff --git a/libcxx/test/std/ranges/range.access/size.pass.cpp b/libcxx/test/std/ranges/range.access/size.pass.cpp
index 0a45a2d7c4988..915e67e194755 100644
--- a/libcxx/test/std/ranges/range.access/size.pass.cpp
+++ b/libcxx/test/std/ranges/range.access/size.pass.cpp
@@ -314,6 +314,11 @@ constexpr bool testRanges() {
return true;
}
+// Test ADL-proofing.
+struct Incomplete;
+template<class T> struct Holder { T t; };
+static_assert(!std::is_invocable_v<RangeSizeT, Holder<Incomplete>*>);
+
int main(int, char**) {
testArrayType();
static_assert(testArrayType());
diff --git a/libcxx/test/std/ranges/range.access/ssize.pass.cpp b/libcxx/test/std/ranges/range.access/ssize.pass.cpp
index 39e7b80e21639..c351928c8fe62 100644
--- a/libcxx/test/std/ranges/range.access/ssize.pass.cpp
+++ b/libcxx/test/std/ranges/range.access/ssize.pass.cpp
@@ -78,6 +78,11 @@ constexpr bool test() {
return true;
}
+// Test ADL-proofing.
+struct Incomplete;
+template<class T> struct Holder { T t; };
+static_assert(!std::is_invocable_v<RangeSSizeT, Holder<Incomplete>*>);
+
int main(int, char**) {
test();
static_assert(test());
diff --git a/libcxx/test/std/ranges/range.req/range.range/range.compile.pass.cpp b/libcxx/test/std/ranges/range.req/range.range/range.compile.pass.cpp
index ecc8048a95866..adf1caa200e62 100644
--- a/libcxx/test/std/ranges/range.req/range.range/range.compile.pass.cpp
+++ b/libcxx/test/std/ranges/range.req/range.range/range.compile.pass.cpp
@@ -46,3 +46,8 @@ struct int_begin_iterator_end {
int* end();
};
static_assert(!std::ranges::range<int_begin_iterator_end>);
+
+// Test ADL-proofing.
+struct Incomplete;
+template<class T> struct Holder { T t; };
+static_assert(!std::ranges::range<Holder<Incomplete>*>);
More information about the libcxx-commits
mailing list