[libcxx-commits] [libcxx] 07a0b0e - [libc++] Properly handle specializations of std::is_placeholder.
Arthur O'Dwyer via libcxx-commits
libcxx-commits at lists.llvm.org
Mon Jan 10 09:39:20 PST 2022
Author: Arthur O'Dwyer
Date: 2022-01-10T12:38:59-05:00
New Revision: 07a0b0ee94880cc193f3c63ebe3c4662c3123606
URL: https://github.com/llvm/llvm-project/commit/07a0b0ee94880cc193f3c63ebe3c4662c3123606
DIFF: https://github.com/llvm/llvm-project/commit/07a0b0ee94880cc193f3c63ebe3c4662c3123606.diff
LOG: [libc++] Properly handle specializations of std::is_placeholder.
Before this patch, the user needed to specialize both of
`is_placeholder<MyType>` and `is_placeholder<const MyType>`.
After this patch, only the former is needed (although the
latter is harmless if provided).
The new tests don't actually fail unless return type deduction
is used, which is a C++14 feature. Specializing `is_placeholder`
is still allowed in C++11, though.
Fixes #51095.
Differential Revision: https://reviews.llvm.org/D116388
Added:
libcxx/test/std/utilities/function.objects/bind/func.bind/func.bind.isbind/specialization.pass.cpp
libcxx/test/std/utilities/function.objects/bind/func.bind/func.bind.isplace/is_placeholder.pass.cpp
libcxx/test/std/utilities/function.objects/bind/func.bind/func.bind.isplace/specialization.pass.cpp
Modified:
libcxx/include/__functional/bind.h
libcxx/test/std/utilities/function.objects/bind/func.bind/func.bind.isbind/is_bind_expression.pass.cpp
Removed:
libcxx/test/std/utilities/function.objects/bind/func.bind/func.bind.isbind/is_placeholder.pass.cpp
################################################################################
diff --git a/libcxx/include/__functional/bind.h b/libcxx/include/__functional/bind.h
index 0eb95c824664e..6fae06ef2549f 100644
--- a/libcxx/include/__functional/bind.h
+++ b/libcxx/include/__functional/bind.h
@@ -23,18 +23,24 @@
_LIBCPP_BEGIN_NAMESPACE_STD
-template<class _Tp> struct __is_bind_expression : public false_type {};
-template<class _Tp> struct _LIBCPP_TEMPLATE_VIS is_bind_expression
- : public __is_bind_expression<typename remove_cv<_Tp>::type> {};
+template<class _Tp>
+struct is_bind_expression : _If<
+ _IsSame<_Tp, typename __uncvref<_Tp>::type>::value,
+ false_type,
+ is_bind_expression<typename __uncvref<_Tp>::type>
+> {};
#if _LIBCPP_STD_VER > 14
template <class _Tp>
inline constexpr size_t is_bind_expression_v = is_bind_expression<_Tp>::value;
#endif
-template<class _Tp> struct __is_placeholder : public integral_constant<int, 0> {};
-template<class _Tp> struct _LIBCPP_TEMPLATE_VIS is_placeholder
- : public __is_placeholder<typename remove_cv<_Tp>::type> {};
+template<class _Tp>
+struct is_placeholder : _If<
+ _IsSame<_Tp, typename __uncvref<_Tp>::type>::value,
+ integral_constant<int, 0>,
+ is_placeholder<typename __uncvref<_Tp>::type>
+> {};
#if _LIBCPP_STD_VER > 14
template <class _Tp>
@@ -73,7 +79,7 @@ _LIBCPP_FUNC_VIS extern const __ph<10> _10;
} // namespace placeholders
template<int _Np>
-struct __is_placeholder<placeholders::__ph<_Np> >
+struct is_placeholder<placeholders::__ph<_Np> >
: public integral_constant<int, _Np> {};
@@ -304,7 +310,7 @@ class __bind
};
template<class _Fp, class ..._BoundArgs>
-struct __is_bind_expression<__bind<_Fp, _BoundArgs...> > : public true_type {};
+struct is_bind_expression<__bind<_Fp, _BoundArgs...> > : public true_type {};
template<class _Rp, class _Fp, class ..._BoundArgs>
class __bind_r
@@ -359,7 +365,7 @@ class __bind_r
};
template<class _Rp, class _Fp, class ..._BoundArgs>
-struct __is_bind_expression<__bind_r<_Rp, _Fp, _BoundArgs...> > : public true_type {};
+struct is_bind_expression<__bind_r<_Rp, _Fp, _BoundArgs...> > : public true_type {};
template<class _Fp, class ..._BoundArgs>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
diff --git a/libcxx/test/std/utilities/function.objects/bind/func.bind/func.bind.isbind/is_bind_expression.pass.cpp b/libcxx/test/std/utilities/function.objects/bind/func.bind/func.bind.isbind/is_bind_expression.pass.cpp
index fd1c6a488886b..f3ef086de3979 100644
--- a/libcxx/test/std/utilities/function.objects/bind/func.bind/func.bind.isbind/is_bind_expression.pass.cpp
+++ b/libcxx/test/std/utilities/function.objects/bind/func.bind/func.bind.isbind/is_bind_expression.pass.cpp
@@ -20,8 +20,15 @@ void
test(const T&)
{
static_assert(std::is_bind_expression<T>::value == Expected, "");
+ LIBCPP_STATIC_ASSERT(std::is_bind_expression<T&>::value == Expected, "");
+ LIBCPP_STATIC_ASSERT(std::is_bind_expression<const T>::value == Expected, "");
+ LIBCPP_STATIC_ASSERT(std::is_bind_expression<const T&>::value == Expected, "");
+
#if TEST_STD_VER > 14
static_assert(std::is_bind_expression_v<T> == Expected, "");
+ LIBCPP_STATIC_ASSERT(std::is_bind_expression_v<T&> == Expected, "");
+ LIBCPP_STATIC_ASSERT(std::is_bind_expression_v<const T> == Expected, "");
+ LIBCPP_STATIC_ASSERT(std::is_bind_expression_v<const T&> == Expected, "");
#endif
}
diff --git a/libcxx/test/std/utilities/function.objects/bind/func.bind/func.bind.isbind/specialization.pass.cpp b/libcxx/test/std/utilities/function.objects/bind/func.bind/func.bind.isbind/specialization.pass.cpp
new file mode 100644
index 0000000000000..cd0457f5dc126
--- /dev/null
+++ b/libcxx/test/std/utilities/function.objects/bind/func.bind/func.bind.isbind/specialization.pass.cpp
@@ -0,0 +1,56 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11
+
+// <functional>
+
+// template<class T> struct is_bind_expression;
+// A program may specialize this template for a program-defined type T
+// to have a base characteristic of true_type to indicate that T should
+// be treated as a subexpression in a bind call.
+// https://llvm.org/PR51753
+
+#include <functional>
+#include <cassert>
+#include <type_traits>
+
+struct MyBind {
+ int operator()(int x, int y) const { return 10*x + y; }
+};
+template<> struct std::is_bind_expression<MyBind> : std::true_type {};
+
+int main(int, char**)
+{
+ {
+ auto f = [](auto x) { return 10*x + 9; };
+ MyBind bindexpr;
+ auto bound = std::bind(f, bindexpr);
+ assert(bound(7, 8) == 789);
+ }
+ {
+ auto f = [](auto x) { return 10*x + 9; };
+ const MyBind bindexpr;
+ auto bound = std::bind(f, bindexpr);
+ assert(bound(7, 8) == 789);
+ }
+ {
+ auto f = [](auto x) { return 10*x + 9; };
+ MyBind bindexpr;
+ auto bound = std::bind(f, std::move(bindexpr));
+ assert(bound(7, 8) == 789);
+ }
+ {
+ auto f = [](auto x) { return 10*x + 9; };
+ const MyBind bindexpr;
+ auto bound = std::bind(f, std::move(bindexpr));
+ assert(bound(7, 8) == 789);
+ }
+
+ return 0;
+}
diff --git a/libcxx/test/std/utilities/function.objects/bind/func.bind/func.bind.isbind/is_placeholder.pass.cpp b/libcxx/test/std/utilities/function.objects/bind/func.bind/func.bind.isplace/is_placeholder.pass.cpp
similarity index 71%
rename from libcxx/test/std/utilities/function.objects/bind/func.bind/func.bind.isbind/is_placeholder.pass.cpp
rename to libcxx/test/std/utilities/function.objects/bind/func.bind/func.bind.isplace/is_placeholder.pass.cpp
index d2ccf1fafdccf..c020ea4f10bbb 100644
--- a/libcxx/test/std/utilities/function.objects/bind/func.bind/func.bind.isbind/is_placeholder.pass.cpp
+++ b/libcxx/test/std/utilities/function.objects/bind/func.bind/func.bind.isplace/is_placeholder.pass.cpp
@@ -18,8 +18,15 @@ void
test(const T&)
{
static_assert(std::is_placeholder<T>::value == Expected, "");
+ LIBCPP_STATIC_ASSERT(std::is_placeholder<T&>::value == Expected, "");
+ LIBCPP_STATIC_ASSERT(std::is_placeholder<const T>::value == Expected, "");
+ LIBCPP_STATIC_ASSERT(std::is_placeholder<const T&>::value == Expected, "");
+
#if TEST_STD_VER > 14
static_assert(std::is_placeholder_v<T> == Expected, "");
+ LIBCPP_STATIC_ASSERT(std::is_placeholder_v<T&> == Expected, "");
+ LIBCPP_STATIC_ASSERT(std::is_placeholder_v<const T> == Expected, "");
+ LIBCPP_STATIC_ASSERT(std::is_placeholder_v<const T&> == Expected, "");
#endif
}
diff --git a/libcxx/test/std/utilities/function.objects/bind/func.bind/func.bind.isplace/specialization.pass.cpp b/libcxx/test/std/utilities/function.objects/bind/func.bind/func.bind.isplace/specialization.pass.cpp
new file mode 100644
index 0000000000000..e0a6c6a95bab8
--- /dev/null
+++ b/libcxx/test/std/utilities/function.objects/bind/func.bind/func.bind.isplace/specialization.pass.cpp
@@ -0,0 +1,54 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11
+
+// <functional>
+
+// template<class T> struct is_placeholder;
+// A program may specialize this template for a program-defined type T
+// to have a base characteristic of integral_constant<int, N> with N > 0
+// to indicate that T should be treated as a placeholder type.
+// https://llvm.org/PR51753
+
+#include <functional>
+#include <cassert>
+#include <type_traits>
+
+struct My2 {};
+template<> struct std::is_placeholder<My2> : std::integral_constant<int, 2> {};
+
+int main(int, char**)
+{
+ {
+ auto f = [](auto x) { return 10*x + 9; };
+ My2 place;
+ auto bound = std::bind(f, place);
+ assert(bound(7, 8) == 89);
+ }
+ {
+ auto f = [](auto x) { return 10*x + 9; };
+ const My2 place;
+ auto bound = std::bind(f, place);
+ assert(bound(7, 8) == 89);
+ }
+ {
+ auto f = [](auto x) { return 10*x + 9; };
+ My2 place;
+ auto bound = std::bind(f, std::move(place));
+ assert(bound(7, 8) == 89);
+ }
+ {
+ auto f = [](auto x) { return 10*x + 9; };
+ const My2 place;
+ auto bound = std::bind(f, std::move(place));
+ assert(bound(7, 8) == 89);
+ }
+
+ return 0;
+}
More information about the libcxx-commits
mailing list