[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