[llvm-branch-commits] [libcxx] 7b00e9f - [libc++] [P1065] Constexpr invoke, reference_wrapper, mem_fn, not_fn, default_searcher.

Arthur O'Dwyer via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Mon Dec 28 10:29:39 PST 2020


Author: Arthur O'Dwyer
Date: 2020-12-28T13:24:07-05:00
New Revision: 7b00e9fae3853d4693e608cc52f6d6da5059f5ff

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

LOG: [libc++] [P1065] Constexpr invoke, reference_wrapper, mem_fn, not_fn, default_searcher.

This completes the implementation of P1065 "constexpr INVOKE":
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1065r2.html

This doesn't yet complete the implementation of P1032 "Misc constexpr bits,"
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1032r1.html
but it does complete all of the <functional> bits, which means
that we can now set `__cpp_lib_constexpr_functional` for C++20.

This could use more constexpr tests for `std::reference_wrapper<T>`,
but the existing tests are extremely non-constexpr-friendly and
so I don't want to get into that rabbit-hole today.

Differential Revision: https://reviews.llvm.org/D93815

Added: 
    libcxx/test/std/utilities/function.objects/func.invoke/invoke_constexpr.pass.cpp

Modified: 
    libcxx/docs/Cxx2aStatusPaperStatus.csv
    libcxx/docs/FeatureTestMacroTable.rst
    libcxx/include/__functional_base
    libcxx/include/functional
    libcxx/include/type_traits
    libcxx/include/version
    libcxx/test/std/language.support/support.limits/support.limits.general/array.version.pass.cpp
    libcxx/test/std/language.support/support.limits/support.limits.general/functional.version.pass.cpp
    libcxx/test/std/language.support/support.limits/support.limits.general/iterator.version.pass.cpp
    libcxx/test/std/language.support/support.limits/support.limits.general/string_view.version.pass.cpp
    libcxx/test/std/language.support/support.limits/support.limits.general/tuple.version.pass.cpp
    libcxx/test/std/language.support/support.limits/support.limits.general/utility.version.pass.cpp
    libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp
    libcxx/test/std/utilities/function.objects/func.memfn/member_data.pass.cpp
    libcxx/test/std/utilities/function.objects/func.memfn/member_function.pass.cpp
    libcxx/test/std/utilities/function.objects/func.memfn/member_function_const.pass.cpp
    libcxx/test/std/utilities/function.objects/func.not_fn/not_fn.pass.cpp
    libcxx/test/std/utilities/function.objects/func.search/func.search.default/default.pass.cpp
    libcxx/test/std/utilities/function.objects/func.search/func.search.default/default.pred.pass.cpp
    libcxx/utils/generate_feature_test_macro_components.py

Removed: 
    


################################################################################
diff  --git a/libcxx/docs/Cxx2aStatusPaperStatus.csv b/libcxx/docs/Cxx2aStatusPaperStatus.csv
index c495e0210cf7..fe5b2f5d4771 100644
--- a/libcxx/docs/Cxx2aStatusPaperStatus.csv
+++ b/libcxx/docs/Cxx2aStatusPaperStatus.csv
@@ -109,7 +109,7 @@
 "`P0980 <https://wg21.link/P0980>`__","LWG","Making std::string constexpr","Cologne","",""
 "`P1004 <https://wg21.link/P1004>`__","LWG","Making std::vector constexpr","Cologne","",""
 "`P1035 <https://wg21.link/P1035>`__","LWG","Input Range Adaptors","Cologne","",""
-"`P1065 <https://wg21.link/P1065>`__","LWG","Constexpr INVOKE","Cologne","",""
+"`P1065 <https://wg21.link/P1065>`__","LWG","Constexpr INVOKE","Cologne","|Complete|","12.0"
 "`P1135 <https://wg21.link/P1135>`__","LWG","The C++20 Synchronization Library","Cologne","|Complete|","11.0"
 "`P1207 <https://wg21.link/P1207>`__","LWG","Movability of Single-pass Iterators","Cologne","",""
 "`P1208 <https://wg21.link/P1208>`__","LWG","Adopt source_location for C++20","Cologne","",""

diff  --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst
index 091d4b795233..5930cdaffaec 100644
--- a/libcxx/docs/FeatureTestMacroTable.rst
+++ b/libcxx/docs/FeatureTestMacroTable.rst
@@ -194,7 +194,7 @@ Status
     ------------------------------------------------- -----------------
     ``__cpp_lib_constexpr_dynamic_alloc``             ``201907L``
     ------------------------------------------------- -----------------
-    ``__cpp_lib_constexpr_misc``                      *unimplemented*
+    ``__cpp_lib_constexpr_functional``                ``201907L``
     ------------------------------------------------- -----------------
     ``__cpp_lib_constexpr_numeric``                   ``201911L``
     ------------------------------------------------- -----------------

diff  --git a/libcxx/include/__functional_base b/libcxx/include/__functional_base
index c84e7eb11567..708c1a23e84b 100644
--- a/libcxx/include/__functional_base
+++ b/libcxx/include/__functional_base
@@ -382,20 +382,23 @@ private:
 
 public:
     // construct/copy/destroy
-    _LIBCPP_INLINE_VISIBILITY reference_wrapper(type& __f) _NOEXCEPT
+    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
+    reference_wrapper(type& __f) _NOEXCEPT
         : __f_(_VSTD::addressof(__f)) {}
 #ifndef _LIBCPP_CXX03_LANG
     private: reference_wrapper(type&&); public: // = delete; // do not bind to temps
 #endif
 
     // access
-    _LIBCPP_INLINE_VISIBILITY operator type&    () const _NOEXCEPT {return *__f_;}
-    _LIBCPP_INLINE_VISIBILITY          type& get() const _NOEXCEPT {return *__f_;}
+    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
+    operator type&() const _NOEXCEPT {return *__f_;}
+    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
+    type& get() const _NOEXCEPT {return *__f_;}
 
 #ifndef _LIBCPP_CXX03_LANG
     // invoke
     template <class... _ArgTypes>
-    _LIBCPP_INLINE_VISIBILITY
+    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
     typename __invoke_of<type&, _ArgTypes...>::type
     operator() (_ArgTypes&&... __args) const {
         return _VSTD::__invoke(get(), _VSTD::forward<_ArgTypes>(__args)...);
@@ -510,7 +513,7 @@ public:
 
 
 template <class _Tp>
-inline _LIBCPP_INLINE_VISIBILITY
+inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
 reference_wrapper<_Tp>
 ref(_Tp& __t) _NOEXCEPT
 {
@@ -518,7 +521,7 @@ ref(_Tp& __t) _NOEXCEPT
 }
 
 template <class _Tp>
-inline _LIBCPP_INLINE_VISIBILITY
+inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
 reference_wrapper<_Tp>
 ref(reference_wrapper<_Tp> __t) _NOEXCEPT
 {
@@ -526,7 +529,7 @@ ref(reference_wrapper<_Tp> __t) _NOEXCEPT
 }
 
 template <class _Tp>
-inline _LIBCPP_INLINE_VISIBILITY
+inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
 reference_wrapper<const _Tp>
 cref(const _Tp& __t) _NOEXCEPT
 {
@@ -534,7 +537,7 @@ cref(const _Tp& __t) _NOEXCEPT
 }
 
 template <class _Tp>
-inline _LIBCPP_INLINE_VISIBILITY
+inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
 reference_wrapper<const _Tp>
 cref(reference_wrapper<_Tp> __t) _NOEXCEPT
 {

diff  --git a/libcxx/include/functional b/libcxx/include/functional
index a54868e82220..dbbebaf82017 100644
--- a/libcxx/include/functional
+++ b/libcxx/include/functional
@@ -213,7 +213,8 @@ public:
 template <class Predicate> // deprecated in C++17
 binary_negate<Predicate> not2(const Predicate& pred);
 
-template <class F> unspecified not_fn(F&& f); // C++17
+template <class F>
+constexpr unspecified not_fn(F&& f); // C++17, constexpr in C++20
 
 template<class T> struct is_bind_expression;
 template<class T> struct is_placeholder;
@@ -226,11 +227,12 @@ template <class T> inline constexpr int is_placeholder_v
 
 
 template<class Fn, class... BoundArgs>
-  unspecified bind(Fn&&, BoundArgs&&...);
+  constexpr unspecified bind(Fn&&, BoundArgs&&...);  // constexpr in C++20
 template<class R, class Fn, class... BoundArgs>
-  unspecified bind(Fn&&, BoundArgs&&...);
+  constexpr unspecified bind(Fn&&, BoundArgs&&...);  // constexpr in C++20
 
 template<class F, class... Args>
+ constexpr // constexpr in C++20
  invoke_result_t<F, Args...> invoke(F&& f, Args&&... args) // C++17
     noexcept(is_nothrow_invocable_v<F, Args...>);
 
@@ -376,7 +378,8 @@ public:
 template <class S, class T>          const_mem_fun_ref_t<S,T>    mem_fun_ref(S (T::*f)() const);   // deprecated in C++11, removed in C++17
 template <class S, class T, class A> const_mem_fun1_ref_t<S,T,A> mem_fun_ref(S (T::*f)(A) const);  // deprecated in C++11, removed in C++17
 
-template<class R, class T> unspecified mem_fn(R T::*);
+template<class R, class T>
+constexpr unspecified mem_fn(R T::*); // constexpr in C++20
 
 class bad_function_call
     : public exception
@@ -1288,12 +1291,13 @@ private:
     type __f_;
 
 public:
-    _LIBCPP_INLINE_VISIBILITY __mem_fn(type __f) _NOEXCEPT : __f_(__f) {}
+    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
+    __mem_fn(type __f) _NOEXCEPT : __f_(__f) {}
 
 #ifndef _LIBCPP_CXX03_LANG
     // invoke
     template <class... _ArgTypes>
-    _LIBCPP_INLINE_VISIBILITY
+    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
     typename __invoke_return<type, _ArgTypes...>::type
     operator() (_ArgTypes&&... __args) const {
         return _VSTD::__invoke(__f_, _VSTD::forward<_ArgTypes>(__args)...);
@@ -1401,7 +1405,7 @@ public:
 };
 
 template<class _Rp, class _Tp>
-inline _LIBCPP_INLINE_VISIBILITY
+inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
 __mem_fn<_Rp _Tp::*>
 mem_fn(_Rp _Tp::* __pm) _NOEXCEPT
 {
@@ -2873,13 +2877,13 @@ public:
                                   !is_same<typename remove_reference<_Gp>::type,
                                            __bind>::value
                                >::type>
-      _LIBCPP_INLINE_VISIBILITY
+      _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
       explicit __bind(_Gp&& __f, _BA&& ...__bound_args)
         : __f_(_VSTD::forward<_Gp>(__f)),
           __bound_args_(_VSTD::forward<_BA>(__bound_args)...) {}
 
     template <class ..._Args>
-        _LIBCPP_INLINE_VISIBILITY
+        _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
         typename __bind_return<_Fd, _Td, tuple<_Args&&...> >::type
         operator()(_Args&& ...__args)
         {
@@ -2888,7 +2892,7 @@ public:
         }
 
     template <class ..._Args>
-        _LIBCPP_INLINE_VISIBILITY
+        _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
         typename __bind_return<const _Fd, const _Td, tuple<_Args&&...> >::type
         operator()(_Args&& ...__args) const
         {
@@ -2918,13 +2922,13 @@ public:
                                   !is_same<typename remove_reference<_Gp>::type,
                                            __bind_r>::value
                                >::type>
-      _LIBCPP_INLINE_VISIBILITY
+      _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
       explicit __bind_r(_Gp&& __f, _BA&& ...__bound_args)
         : base(_VSTD::forward<_Gp>(__f),
                _VSTD::forward<_BA>(__bound_args)...) {}
 
     template <class ..._Args>
-        _LIBCPP_INLINE_VISIBILITY
+        _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
         typename enable_if
         <
             is_convertible<typename __bind_return<_Fd, _Td, tuple<_Args&&...> >::type,
@@ -2938,7 +2942,7 @@ public:
         }
 
     template <class ..._Args>
-        _LIBCPP_INLINE_VISIBILITY
+        _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
         typename enable_if
         <
             is_convertible<typename __bind_return<const _Fd, const _Td, tuple<_Args&&...> >::type,
@@ -2956,7 +2960,7 @@ template<class _Rp, class _Fp, class ..._BoundArgs>
 struct __is_bind_expression<__bind_r<_Rp, _Fp, _BoundArgs...> > : public true_type {};
 
 template<class _Fp, class ..._BoundArgs>
-inline _LIBCPP_INLINE_VISIBILITY
+inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
 __bind<_Fp, _BoundArgs...>
 bind(_Fp&& __f, _BoundArgs&&... __bound_args)
 {
@@ -2965,7 +2969,7 @@ bind(_Fp&& __f, _BoundArgs&&... __bound_args)
 }
 
 template<class _Rp, class _Fp, class ..._BoundArgs>
-inline _LIBCPP_INLINE_VISIBILITY
+inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
 __bind_r<_Rp, _Fp, _BoundArgs...>
 bind(_Fp&& __f, _BoundArgs&&... __bound_args)
 {
@@ -2978,7 +2982,7 @@ bind(_Fp&& __f, _BoundArgs&&... __bound_args)
 #if _LIBCPP_STD_VER > 14
 
 template <class _Fn, class ..._Args>
-invoke_result_t<_Fn, _Args...>
+_LIBCPP_CONSTEXPR_AFTER_CXX17 invoke_result_t<_Fn, _Args...>
 invoke(_Fn&& __f, _Args&&... __args)
     noexcept(is_nothrow_invocable_v<_Fn, _Args...>)
 {
@@ -2993,21 +2997,21 @@ public:
     __not_fn_imp() = delete;
 
     template <class ..._Args>
-    _LIBCPP_INLINE_VISIBILITY
+    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
     auto operator()(_Args&& ...__args) &
             noexcept(noexcept(!_VSTD::invoke(__fd, _VSTD::forward<_Args>(__args)...)))
         -> decltype(          !_VSTD::invoke(__fd, _VSTD::forward<_Args>(__args)...))
         { return              !_VSTD::invoke(__fd, _VSTD::forward<_Args>(__args)...); }
 
     template <class ..._Args>
-    _LIBCPP_INLINE_VISIBILITY
+    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
     auto operator()(_Args&& ...__args) &&
             noexcept(noexcept(!_VSTD::invoke(_VSTD::move(__fd), _VSTD::forward<_Args>(__args)...)))
         -> decltype(          !_VSTD::invoke(_VSTD::move(__fd), _VSTD::forward<_Args>(__args)...))
         { return              !_VSTD::invoke(_VSTD::move(__fd), _VSTD::forward<_Args>(__args)...); }
 
     template <class ..._Args>
-    _LIBCPP_INLINE_VISIBILITY
+    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
     auto operator()(_Args&& ...__args) const&
             noexcept(noexcept(!_VSTD::invoke(__fd, _VSTD::forward<_Args>(__args)...)))
         -> decltype(          !_VSTD::invoke(__fd, _VSTD::forward<_Args>(__args)...))
@@ -3015,7 +3019,7 @@ public:
 
 
     template <class ..._Args>
-    _LIBCPP_INLINE_VISIBILITY
+    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
     auto operator()(_Args&& ...__args) const&&
             noexcept(noexcept(!_VSTD::invoke(_VSTD::move(__fd), _VSTD::forward<_Args>(__args)...)))
         -> decltype(          !_VSTD::invoke(_VSTD::move(__fd), _VSTD::forward<_Args>(__args)...))
@@ -3024,17 +3028,17 @@ public:
 private:
     template <class _RawFunc,
               class = enable_if_t<!is_same<decay_t<_RawFunc>, __not_fn_imp>::value>>
-    _LIBCPP_INLINE_VISIBILITY
+    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
     explicit __not_fn_imp(_RawFunc&& __rf)
         : __fd(_VSTD::forward<_RawFunc>(__rf)) {}
 
     template <class _RawFunc>
-    friend inline _LIBCPP_INLINE_VISIBILITY
+    friend inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
     __not_fn_imp<decay_t<_RawFunc>> not_fn(_RawFunc&&);
 };
 
 template <class _RawFunc>
-inline _LIBCPP_INLINE_VISIBILITY
+inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
 __not_fn_imp<decay_t<_RawFunc>> not_fn(_RawFunc&& __fn) {
     return __not_fn_imp<decay_t<_RawFunc>>(_VSTD::forward<_RawFunc>(__fn));
 }
@@ -3131,13 +3135,13 @@ __search(_RandomAccessIterator1 __first1, _RandomAccessIterator1 __last1,
 template<class _ForwardIterator, class _BinaryPredicate = equal_to<>>
 class _LIBCPP_TYPE_VIS default_searcher {
 public:
-    _LIBCPP_INLINE_VISIBILITY
+    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
     default_searcher(_ForwardIterator __f, _ForwardIterator __l,
                        _BinaryPredicate __p = _BinaryPredicate())
         : __first_(__f), __last_(__l), __pred_(__p) {}
 
     template <typename _ForwardIterator2>
-    _LIBCPP_INLINE_VISIBILITY
+    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
     pair<_ForwardIterator2, _ForwardIterator2>
     operator () (_ForwardIterator2 __f, _ForwardIterator2 __l) const
     {

diff  --git a/libcxx/include/type_traits b/libcxx/include/type_traits
index c1633f19c51f..99b2a8f9f025 100644
--- a/libcxx/include/type_traits
+++ b/libcxx/include/type_traits
@@ -3584,7 +3584,7 @@ auto __invoke_constexpr(__any, _Args&& ...__args) -> __nat;
 template <class _Fp, class _A0, class ..._Args,
           class = __enable_if_bullet1<_Fp, _A0>>
 inline _LIBCPP_INLINE_VISIBILITY
-auto
+_LIBCPP_CONSTEXPR_AFTER_CXX17 auto
 __invoke(_Fp&& __f, _A0&& __a0, _Args&& ...__args)
 _LIBCPP_INVOKE_RETURN((_VSTD::forward<_A0>(__a0).*__f)(_VSTD::forward<_Args>(__args)...))
 
@@ -3598,7 +3598,7 @@ _LIBCPP_INVOKE_RETURN((_VSTD::forward<_A0>(__a0).*__f)(_VSTD::forward<_Args>(__a
 template <class _Fp, class _A0, class ..._Args,
           class = __enable_if_bullet2<_Fp, _A0>>
 inline _LIBCPP_INLINE_VISIBILITY
-auto
+_LIBCPP_CONSTEXPR_AFTER_CXX17 auto
 __invoke(_Fp&& __f, _A0&& __a0, _Args&& ...__args)
 _LIBCPP_INVOKE_RETURN((__a0.get().*__f)(_VSTD::forward<_Args>(__args)...))
 
@@ -3612,7 +3612,7 @@ _LIBCPP_INVOKE_RETURN((__a0.get().*__f)(_VSTD::forward<_Args>(__args)...))
 template <class _Fp, class _A0, class ..._Args,
           class = __enable_if_bullet3<_Fp, _A0>>
 inline _LIBCPP_INLINE_VISIBILITY
-auto
+_LIBCPP_CONSTEXPR_AFTER_CXX17 auto
 __invoke(_Fp&& __f, _A0&& __a0, _Args&& ...__args)
 _LIBCPP_INVOKE_RETURN(((*_VSTD::forward<_A0>(__a0)).*__f)(_VSTD::forward<_Args>(__args)...))
 
@@ -3628,7 +3628,7 @@ _LIBCPP_INVOKE_RETURN(((*_VSTD::forward<_A0>(__a0)).*__f)(_VSTD::forward<_Args>(
 template <class _Fp, class _A0,
           class = __enable_if_bullet4<_Fp, _A0>>
 inline _LIBCPP_INLINE_VISIBILITY
-auto
+_LIBCPP_CONSTEXPR_AFTER_CXX17 auto
 __invoke(_Fp&& __f, _A0&& __a0)
 _LIBCPP_INVOKE_RETURN(_VSTD::forward<_A0>(__a0).*__f)
 
@@ -3642,7 +3642,7 @@ _LIBCPP_INVOKE_RETURN(_VSTD::forward<_A0>(__a0).*__f)
 template <class _Fp, class _A0,
           class = __enable_if_bullet5<_Fp, _A0>>
 inline _LIBCPP_INLINE_VISIBILITY
-auto
+_LIBCPP_CONSTEXPR_AFTER_CXX17 auto
 __invoke(_Fp&& __f, _A0&& __a0)
 _LIBCPP_INVOKE_RETURN(__a0.get().*__f)
 
@@ -3656,7 +3656,7 @@ _LIBCPP_INVOKE_RETURN(__a0.get().*__f)
 template <class _Fp, class _A0,
           class = __enable_if_bullet6<_Fp, _A0>>
 inline _LIBCPP_INLINE_VISIBILITY
-auto
+_LIBCPP_CONSTEXPR_AFTER_CXX17 auto
 __invoke(_Fp&& __f, _A0&& __a0)
 _LIBCPP_INVOKE_RETURN((*_VSTD::forward<_A0>(__a0)).*__f)
 
@@ -3671,7 +3671,7 @@ _LIBCPP_INVOKE_RETURN((*_VSTD::forward<_A0>(__a0)).*__f)
 
 template <class _Fp, class ..._Args>
 inline _LIBCPP_INLINE_VISIBILITY
-auto
+_LIBCPP_CONSTEXPR_AFTER_CXX17 auto
 __invoke(_Fp&& __f, _Args&& ...__args)
 _LIBCPP_INVOKE_RETURN(_VSTD::forward<_Fp>(__f)(_VSTD::forward<_Args>(__args)...))
 

diff  --git a/libcxx/include/version b/libcxx/include/version
index e32f47ae837a..dde6ca165b35 100644
--- a/libcxx/include/version
+++ b/libcxx/include/version
@@ -46,8 +46,7 @@ __cpp_lib_clamp                                         201603L <algorithm>
 __cpp_lib_complex_udls                                  201309L <complex>
 __cpp_lib_concepts                                      201806L <concepts>
 __cpp_lib_constexpr_dynamic_alloc                       201907L <memory>
-__cpp_lib_constexpr_misc                                201811L <array> <functional> <iterator>
-                                                                <string_view> <tuple> <utility>
+__cpp_lib_constexpr_functional                          201907L <functional>
 __cpp_lib_constexpr_numeric                             201911L <numeric>
 __cpp_lib_constexpr_swap_algorithms                     201806L <algorithm>
 __cpp_lib_constexpr_utility                             201811L <utility>
@@ -254,7 +253,7 @@ __cpp_lib_void_t                                        201411L <type_traits>
 # endif
 // # define __cpp_lib_concepts                             201806L
 # define __cpp_lib_constexpr_dynamic_alloc              201907L
-// # define __cpp_lib_constexpr_misc                       201811L
+# define __cpp_lib_constexpr_functional                 201907L
 # define __cpp_lib_constexpr_numeric                    201911L
 // # define __cpp_lib_constexpr_swap_algorithms            201806L
 # define __cpp_lib_constexpr_utility                    201811L

diff  --git a/libcxx/test/std/language.support/support.limits/support.limits.general/array.version.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/array.version.pass.cpp
index 933420be50c9..c2e831a3af31 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/array.version.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/array.version.pass.cpp
@@ -16,7 +16,6 @@
 /*  Constant                                Value
     __cpp_lib_array_constexpr               201603L [C++17]
                                             201811L [C++2a]
-    __cpp_lib_constexpr_misc                201811L [C++2a]
     __cpp_lib_nonmember_container_access    201411L [C++17]
     __cpp_lib_to_array                      201907L [C++2a]
 */
@@ -30,10 +29,6 @@
 #   error "__cpp_lib_array_constexpr should not be defined before c++17"
 # endif
 
-# ifdef __cpp_lib_constexpr_misc
-#   error "__cpp_lib_constexpr_misc should not be defined before c++2a"
-# endif
-
 # ifdef __cpp_lib_nonmember_container_access
 #   error "__cpp_lib_nonmember_container_access should not be defined before c++17"
 # endif
@@ -48,10 +43,6 @@
 #   error "__cpp_lib_array_constexpr should not be defined before c++17"
 # endif
 
-# ifdef __cpp_lib_constexpr_misc
-#   error "__cpp_lib_constexpr_misc should not be defined before c++2a"
-# endif
-
 # ifdef __cpp_lib_nonmember_container_access
 #   error "__cpp_lib_nonmember_container_access should not be defined before c++17"
 # endif
@@ -69,10 +60,6 @@
 #   error "__cpp_lib_array_constexpr should have the value 201603L in c++17"
 # endif
 
-# ifdef __cpp_lib_constexpr_misc
-#   error "__cpp_lib_constexpr_misc should not be defined before c++2a"
-# endif
-
 # ifndef __cpp_lib_nonmember_container_access
 #   error "__cpp_lib_nonmember_container_access should be defined in c++17"
 # endif
@@ -93,19 +80,6 @@
 #   error "__cpp_lib_array_constexpr should have the value 201811L in c++2a"
 # endif
 
-# if !defined(_LIBCPP_VERSION)
-#   ifndef __cpp_lib_constexpr_misc
-#     error "__cpp_lib_constexpr_misc should be defined in c++2a"
-#   endif
-#   if __cpp_lib_constexpr_misc != 201811L
-#     error "__cpp_lib_constexpr_misc should have the value 201811L in c++2a"
-#   endif
-# else // _LIBCPP_VERSION
-#   ifdef __cpp_lib_constexpr_misc
-#     error "__cpp_lib_constexpr_misc should not be defined because it is unimplemented in libc++!"
-#   endif
-# endif
-
 # ifndef __cpp_lib_nonmember_container_access
 #   error "__cpp_lib_nonmember_container_access should be defined in c++2a"
 # endif

diff  --git a/libcxx/test/std/language.support/support.limits/support.limits.general/functional.version.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/functional.version.pass.cpp
index a29a1d708a30..2b556010f00e 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/functional.version.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/functional.version.pass.cpp
@@ -16,7 +16,7 @@
 /*  Constant                           Value
     __cpp_lib_bind_front               201811L [C++2a]
     __cpp_lib_boyer_moore_searcher     201603L [C++17]
-    __cpp_lib_constexpr_misc           201811L [C++2a]
+    __cpp_lib_constexpr_functional     201907L [C++2a]
     __cpp_lib_invoke                   201411L [C++17]
     __cpp_lib_not_fn                   201603L [C++17]
     __cpp_lib_ranges                   201811L [C++2a]
@@ -38,8 +38,8 @@
 #   error "__cpp_lib_boyer_moore_searcher should not be defined before c++17"
 # endif
 
-# ifdef __cpp_lib_constexpr_misc
-#   error "__cpp_lib_constexpr_misc should not be defined before c++2a"
+# ifdef __cpp_lib_constexpr_functional
+#   error "__cpp_lib_constexpr_functional should not be defined before c++2a"
 # endif
 
 # ifdef __cpp_lib_invoke
@@ -72,8 +72,8 @@
 #   error "__cpp_lib_boyer_moore_searcher should not be defined before c++17"
 # endif
 
-# ifdef __cpp_lib_constexpr_misc
-#   error "__cpp_lib_constexpr_misc should not be defined before c++2a"
+# ifdef __cpp_lib_constexpr_functional
+#   error "__cpp_lib_constexpr_functional should not be defined before c++2a"
 # endif
 
 # ifdef __cpp_lib_invoke
@@ -121,8 +121,8 @@
 #   endif
 # endif
 
-# ifdef __cpp_lib_constexpr_misc
-#   error "__cpp_lib_constexpr_misc should not be defined before c++2a"
+# ifdef __cpp_lib_constexpr_functional
+#   error "__cpp_lib_constexpr_functional should not be defined before c++2a"
 # endif
 
 # ifndef __cpp_lib_invoke
@@ -185,17 +185,11 @@
 #   endif
 # endif
 
-# if !defined(_LIBCPP_VERSION)
-#   ifndef __cpp_lib_constexpr_misc
-#     error "__cpp_lib_constexpr_misc should be defined in c++2a"
-#   endif
-#   if __cpp_lib_constexpr_misc != 201811L
-#     error "__cpp_lib_constexpr_misc should have the value 201811L in c++2a"
-#   endif
-# else // _LIBCPP_VERSION
-#   ifdef __cpp_lib_constexpr_misc
-#     error "__cpp_lib_constexpr_misc should not be defined because it is unimplemented in libc++!"
-#   endif
+# ifndef __cpp_lib_constexpr_functional
+#   error "__cpp_lib_constexpr_functional should be defined in c++2a"
+# endif
+# if __cpp_lib_constexpr_functional != 201907L
+#   error "__cpp_lib_constexpr_functional should have the value 201907L in c++2a"
 # endif
 
 # ifndef __cpp_lib_invoke

diff  --git a/libcxx/test/std/language.support/support.limits/support.limits.general/iterator.version.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/iterator.version.pass.cpp
index 4e68cf9a7232..0c128f5a46de 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/iterator.version.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/iterator.version.pass.cpp
@@ -16,7 +16,6 @@
 /*  Constant                                Value
     __cpp_lib_array_constexpr               201603L [C++17]
                                             201811L [C++2a]
-    __cpp_lib_constexpr_misc                201811L [C++2a]
     __cpp_lib_make_reverse_iterator         201402L [C++14]
     __cpp_lib_nonmember_container_access    201411L [C++17]
     __cpp_lib_null_iterators                201304L [C++14]
@@ -32,10 +31,6 @@
 #   error "__cpp_lib_array_constexpr should not be defined before c++17"
 # endif
 
-# ifdef __cpp_lib_constexpr_misc
-#   error "__cpp_lib_constexpr_misc should not be defined before c++2a"
-# endif
-
 # ifdef __cpp_lib_make_reverse_iterator
 #   error "__cpp_lib_make_reverse_iterator should not be defined before c++14"
 # endif
@@ -58,10 +53,6 @@
 #   error "__cpp_lib_array_constexpr should not be defined before c++17"
 # endif
 
-# ifdef __cpp_lib_constexpr_misc
-#   error "__cpp_lib_constexpr_misc should not be defined before c++2a"
-# endif
-
 # ifndef __cpp_lib_make_reverse_iterator
 #   error "__cpp_lib_make_reverse_iterator should be defined in c++14"
 # endif
@@ -93,10 +84,6 @@
 #   error "__cpp_lib_array_constexpr should have the value 201603L in c++17"
 # endif
 
-# ifdef __cpp_lib_constexpr_misc
-#   error "__cpp_lib_constexpr_misc should not be defined before c++2a"
-# endif
-
 # ifndef __cpp_lib_make_reverse_iterator
 #   error "__cpp_lib_make_reverse_iterator should be defined in c++17"
 # endif
@@ -131,19 +118,6 @@
 #   error "__cpp_lib_array_constexpr should have the value 201811L in c++2a"
 # endif
 
-# if !defined(_LIBCPP_VERSION)
-#   ifndef __cpp_lib_constexpr_misc
-#     error "__cpp_lib_constexpr_misc should be defined in c++2a"
-#   endif
-#   if __cpp_lib_constexpr_misc != 201811L
-#     error "__cpp_lib_constexpr_misc should have the value 201811L in c++2a"
-#   endif
-# else // _LIBCPP_VERSION
-#   ifdef __cpp_lib_constexpr_misc
-#     error "__cpp_lib_constexpr_misc should not be defined because it is unimplemented in libc++!"
-#   endif
-# endif
-
 # ifndef __cpp_lib_make_reverse_iterator
 #   error "__cpp_lib_make_reverse_iterator should be defined in c++2a"
 # endif

diff  --git a/libcxx/test/std/language.support/support.limits/support.limits.general/string_view.version.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/string_view.version.pass.cpp
index 816083e0d7f3..1fca20d41f8c 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/string_view.version.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/string_view.version.pass.cpp
@@ -13,10 +13,9 @@
 
 // Test the feature test macros defined by <string_view>
 
-/*  Constant                    Value
-    __cpp_lib_char8_t           201811L [C++2a]
-    __cpp_lib_constexpr_misc    201811L [C++2a]
-    __cpp_lib_string_view       201606L [C++17]
+/*  Constant                 Value
+    __cpp_lib_char8_t        201811L [C++2a]
+    __cpp_lib_string_view    201606L [C++17]
 */
 
 #include <string_view>
@@ -28,10 +27,6 @@
 #   error "__cpp_lib_char8_t should not be defined before c++2a"
 # endif
 
-# ifdef __cpp_lib_constexpr_misc
-#   error "__cpp_lib_constexpr_misc should not be defined before c++2a"
-# endif
-
 # ifdef __cpp_lib_string_view
 #   error "__cpp_lib_string_view should not be defined before c++17"
 # endif
@@ -42,10 +37,6 @@
 #   error "__cpp_lib_char8_t should not be defined before c++2a"
 # endif
 
-# ifdef __cpp_lib_constexpr_misc
-#   error "__cpp_lib_constexpr_misc should not be defined before c++2a"
-# endif
-
 # ifdef __cpp_lib_string_view
 #   error "__cpp_lib_string_view should not be defined before c++17"
 # endif
@@ -56,10 +47,6 @@
 #   error "__cpp_lib_char8_t should not be defined before c++2a"
 # endif
 
-# ifdef __cpp_lib_constexpr_misc
-#   error "__cpp_lib_constexpr_misc should not be defined before c++2a"
-# endif
-
 # ifndef __cpp_lib_string_view
 #   error "__cpp_lib_string_view should be defined in c++17"
 # endif
@@ -82,19 +69,6 @@
 #   endif
 # endif
 
-# if !defined(_LIBCPP_VERSION)
-#   ifndef __cpp_lib_constexpr_misc
-#     error "__cpp_lib_constexpr_misc should be defined in c++2a"
-#   endif
-#   if __cpp_lib_constexpr_misc != 201811L
-#     error "__cpp_lib_constexpr_misc should have the value 201811L in c++2a"
-#   endif
-# else // _LIBCPP_VERSION
-#   ifdef __cpp_lib_constexpr_misc
-#     error "__cpp_lib_constexpr_misc should not be defined because it is unimplemented in libc++!"
-#   endif
-# endif
-
 # ifndef __cpp_lib_string_view
 #   error "__cpp_lib_string_view should be defined in c++2a"
 # endif

diff  --git a/libcxx/test/std/language.support/support.limits/support.limits.general/tuple.version.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/tuple.version.pass.cpp
index 5c1e6580c57d..e4c3d54d1982 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/tuple.version.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/tuple.version.pass.cpp
@@ -15,7 +15,6 @@
 
 /*  Constant                     Value
     __cpp_lib_apply              201603L [C++17]
-    __cpp_lib_constexpr_misc     201811L [C++2a]
     __cpp_lib_make_from_tuple    201606L [C++17]
     __cpp_lib_tuple_element_t    201402L [C++14]
     __cpp_lib_tuples_by_type     201304L [C++14]
@@ -30,10 +29,6 @@
 #   error "__cpp_lib_apply should not be defined before c++17"
 # endif
 
-# ifdef __cpp_lib_constexpr_misc
-#   error "__cpp_lib_constexpr_misc should not be defined before c++2a"
-# endif
-
 # ifdef __cpp_lib_make_from_tuple
 #   error "__cpp_lib_make_from_tuple should not be defined before c++17"
 # endif
@@ -52,10 +47,6 @@
 #   error "__cpp_lib_apply should not be defined before c++17"
 # endif
 
-# ifdef __cpp_lib_constexpr_misc
-#   error "__cpp_lib_constexpr_misc should not be defined before c++2a"
-# endif
-
 # ifdef __cpp_lib_make_from_tuple
 #   error "__cpp_lib_make_from_tuple should not be defined before c++17"
 # endif
@@ -83,10 +74,6 @@
 #   error "__cpp_lib_apply should have the value 201603L in c++17"
 # endif
 
-# ifdef __cpp_lib_constexpr_misc
-#   error "__cpp_lib_constexpr_misc should not be defined before c++2a"
-# endif
-
 # ifndef __cpp_lib_make_from_tuple
 #   error "__cpp_lib_make_from_tuple should be defined in c++17"
 # endif
@@ -117,19 +104,6 @@
 #   error "__cpp_lib_apply should have the value 201603L in c++2a"
 # endif
 
-# if !defined(_LIBCPP_VERSION)
-#   ifndef __cpp_lib_constexpr_misc
-#     error "__cpp_lib_constexpr_misc should be defined in c++2a"
-#   endif
-#   if __cpp_lib_constexpr_misc != 201811L
-#     error "__cpp_lib_constexpr_misc should have the value 201811L in c++2a"
-#   endif
-# else // _LIBCPP_VERSION
-#   ifdef __cpp_lib_constexpr_misc
-#     error "__cpp_lib_constexpr_misc should not be defined because it is unimplemented in libc++!"
-#   endif
-# endif
-
 # ifndef __cpp_lib_make_from_tuple
 #   error "__cpp_lib_make_from_tuple should be defined in c++2a"
 # endif

diff  --git a/libcxx/test/std/language.support/support.limits/support.limits.general/utility.version.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/utility.version.pass.cpp
index e595a99a749f..63f755e66047 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/utility.version.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/utility.version.pass.cpp
@@ -15,7 +15,6 @@
 
 /*  Constant                       Value
     __cpp_lib_as_const             201510L [C++17]
-    __cpp_lib_constexpr_misc       201811L [C++2a]
     __cpp_lib_constexpr_utility    201811L [C++2a]
     __cpp_lib_exchange_function    201304L [C++14]
     __cpp_lib_integer_sequence     201304L [C++14]
@@ -32,10 +31,6 @@
 #   error "__cpp_lib_as_const should not be defined before c++17"
 # endif
 
-# ifdef __cpp_lib_constexpr_misc
-#   error "__cpp_lib_constexpr_misc should not be defined before c++2a"
-# endif
-
 # ifdef __cpp_lib_constexpr_utility
 #   error "__cpp_lib_constexpr_utility should not be defined before c++2a"
 # endif
@@ -62,10 +57,6 @@
 #   error "__cpp_lib_as_const should not be defined before c++17"
 # endif
 
-# ifdef __cpp_lib_constexpr_misc
-#   error "__cpp_lib_constexpr_misc should not be defined before c++2a"
-# endif
-
 # ifdef __cpp_lib_constexpr_utility
 #   error "__cpp_lib_constexpr_utility should not be defined before c++2a"
 # endif
@@ -104,10 +95,6 @@
 #   error "__cpp_lib_as_const should have the value 201510L in c++17"
 # endif
 
-# ifdef __cpp_lib_constexpr_misc
-#   error "__cpp_lib_constexpr_misc should not be defined before c++2a"
-# endif
-
 # ifdef __cpp_lib_constexpr_utility
 #   error "__cpp_lib_constexpr_utility should not be defined before c++2a"
 # endif
@@ -155,19 +142,6 @@
 #   error "__cpp_lib_as_const should have the value 201510L in c++2a"
 # endif
 
-# if !defined(_LIBCPP_VERSION)
-#   ifndef __cpp_lib_constexpr_misc
-#     error "__cpp_lib_constexpr_misc should be defined in c++2a"
-#   endif
-#   if __cpp_lib_constexpr_misc != 201811L
-#     error "__cpp_lib_constexpr_misc should have the value 201811L in c++2a"
-#   endif
-# else // _LIBCPP_VERSION
-#   ifdef __cpp_lib_constexpr_misc
-#     error "__cpp_lib_constexpr_misc should not be defined because it is unimplemented in libc++!"
-#   endif
-# endif
-
 # ifndef __cpp_lib_constexpr_utility
 #   error "__cpp_lib_constexpr_utility should be defined in c++2a"
 # endif

diff  --git a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp
index 783c5449038c..e37907185db1 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.pass.cpp
@@ -41,7 +41,7 @@
     __cpp_lib_complex_udls                         201309L [C++14]
     __cpp_lib_concepts                             201806L [C++2a]
     __cpp_lib_constexpr_dynamic_alloc              201907L [C++2a]
-    __cpp_lib_constexpr_misc                       201811L [C++2a]
+    __cpp_lib_constexpr_functional                 201907L [C++2a]
     __cpp_lib_constexpr_numeric                    201911L [C++2a]
     __cpp_lib_constexpr_swap_algorithms            201806L [C++2a]
     __cpp_lib_constexpr_utility                    201811L [C++2a]
@@ -224,8 +224,8 @@
 #   error "__cpp_lib_constexpr_dynamic_alloc should not be defined before c++2a"
 # endif
 
-# ifdef __cpp_lib_constexpr_misc
-#   error "__cpp_lib_constexpr_misc should not be defined before c++2a"
+# ifdef __cpp_lib_constexpr_functional
+#   error "__cpp_lib_constexpr_functional should not be defined before c++2a"
 # endif
 
 # ifdef __cpp_lib_constexpr_numeric
@@ -620,8 +620,8 @@
 #   error "__cpp_lib_constexpr_dynamic_alloc should not be defined before c++2a"
 # endif
 
-# ifdef __cpp_lib_constexpr_misc
-#   error "__cpp_lib_constexpr_misc should not be defined before c++2a"
+# ifdef __cpp_lib_constexpr_functional
+#   error "__cpp_lib_constexpr_functional should not be defined before c++2a"
 # endif
 
 # ifdef __cpp_lib_constexpr_numeric
@@ -1130,8 +1130,8 @@
 #   error "__cpp_lib_constexpr_dynamic_alloc should not be defined before c++2a"
 # endif
 
-# ifdef __cpp_lib_constexpr_misc
-#   error "__cpp_lib_constexpr_misc should not be defined before c++2a"
+# ifdef __cpp_lib_constexpr_functional
+#   error "__cpp_lib_constexpr_functional should not be defined before c++2a"
 # endif
 
 # ifdef __cpp_lib_constexpr_numeric
@@ -1904,17 +1904,11 @@
 #   error "__cpp_lib_constexpr_dynamic_alloc should have the value 201907L in c++2a"
 # endif
 
-# if !defined(_LIBCPP_VERSION)
-#   ifndef __cpp_lib_constexpr_misc
-#     error "__cpp_lib_constexpr_misc should be defined in c++2a"
-#   endif
-#   if __cpp_lib_constexpr_misc != 201811L
-#     error "__cpp_lib_constexpr_misc should have the value 201811L in c++2a"
-#   endif
-# else // _LIBCPP_VERSION
-#   ifdef __cpp_lib_constexpr_misc
-#     error "__cpp_lib_constexpr_misc should not be defined because it is unimplemented in libc++!"
-#   endif
+# ifndef __cpp_lib_constexpr_functional
+#   error "__cpp_lib_constexpr_functional should be defined in c++2a"
+# endif
+# if __cpp_lib_constexpr_functional != 201907L
+#   error "__cpp_lib_constexpr_functional should have the value 201907L in c++2a"
 # endif
 
 # ifndef __cpp_lib_constexpr_numeric

diff  --git a/libcxx/test/std/utilities/function.objects/func.invoke/invoke_constexpr.pass.cpp b/libcxx/test/std/utilities/function.objects/func.invoke/invoke_constexpr.pass.cpp
new file mode 100644
index 000000000000..8bfc7428fad9
--- /dev/null
+++ b/libcxx/test/std/utilities/function.objects/func.invoke/invoke_constexpr.pass.cpp
@@ -0,0 +1,279 @@
+//===----------------------------------------------------------------------===//
+//
+// 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, c++14, c++17
+
+// <functional>
+
+// template<class F, class... Args>
+// constexpr  // constexpr in C++20
+// invoke_result_t<F, Args...> invoke(F&& f, Args&&... args)
+//     noexcept(is_nothrow_invocable_v<_Fn, _Args...>);
+
+/// C++14 [func.def] 20.9.0
+/// (1) The following definitions apply to this Clause:
+/// (2) A call signature is the name of a return type followed by a parenthesized
+///     comma-separated list of zero or more argument types.
+/// (3) A callable type is a function object type (20.9) or a pointer to member.
+/// (4) A callable object is an object of a callable type.
+/// (5) A call wrapper type is a type that holds a callable object and supports
+///     a call operation that forwards to that object.
+/// (6) A call wrapper is an object of a call wrapper type.
+/// (7) A target object is the callable object held by a call wrapper.
+
+/// C++14 [func.require] 20.9.1
+///
+/// Define INVOKE (f, t1, t2, ..., tN) as follows:
+///   (1.1) - (t1.*f)(t2, ..., tN) when f is a pointer to a member function of a class T and t1 is an object of
+///   type T or a reference to an object of type T or a reference to an object of a type derived from T;
+///   (1.2) - ((*t1).*f)(t2, ..., tN) when f is a pointer to a member function of a class T and t1 is not one of
+///   the types described in the previous item;
+///   (1.3) - t1.*f when N == 1 and f is a pointer to member data of a class T and t1 is an object of type T or a
+///   reference to an object of type T or a reference to an object of a type derived from T;
+///   (1.4) - (*t1).*f when N == 1 and f is a pointer to member data of a class T and t1 is not one of the types
+///   described in the previous item;
+///   (1.5) - f(t1, t2, ..., tN) in all other cases.
+
+#include <functional>
+#include <type_traits>
+#include <utility> // for std::move
+#include <cassert>
+
+#include "test_macros.h"
+
+struct NonCopyable {
+    constexpr NonCopyable() {}
+private:
+    NonCopyable(NonCopyable const&) = delete;
+    NonCopyable& operator=(NonCopyable const&) = delete;
+};
+
+struct TestClass {
+    constexpr explicit TestClass(int x) : data(x) {}
+
+    constexpr int& operator()(NonCopyable&&) & { return data; }
+    constexpr int const& operator()(NonCopyable&&) const & { return data; }
+
+    constexpr int&& operator()(NonCopyable&&) && { return std::move(data); }
+    constexpr int const&& operator()(NonCopyable&&) const && { return std::move(data); }
+
+    int data;
+private:
+    TestClass(TestClass const&) = delete;
+    TestClass& operator=(TestClass const&) = delete;
+};
+
+struct DerivedFromTestClass : public TestClass {
+    constexpr explicit DerivedFromTestClass(int x) : TestClass(x) {}
+};
+
+static constexpr int data = 42;
+constexpr const int& foo(NonCopyable&&) {
+    return data;
+}
+
+template <class Signature,  class Expect, class Functor>
+constexpr void test_b12(Functor&& f) {
+    // Create the callable object.
+    typedef Signature TestClass::*ClassFunc;
+    ClassFunc func_ptr = &TestClass::operator();
+
+    // Create the dummy arg.
+    NonCopyable arg;
+
+    // Check that the deduced return type of invoke is what is expected.
+    typedef decltype(
+        std::invoke(func_ptr, std::forward<Functor>(f), std::move(arg))
+    ) DeducedReturnType;
+    static_assert((std::is_same<DeducedReturnType, Expect>::value), "");
+
+    // Check that result_of_t matches Expect.
+    typedef typename std::result_of<ClassFunc&&(Functor&&, NonCopyable&&)>::type
+      ResultOfReturnType;
+    static_assert((std::is_same<ResultOfReturnType, Expect>::value), "");
+
+    // Run invoke and check the return value.
+    DeducedReturnType ret =
+            std::invoke(func_ptr, std::forward<Functor>(f), std::move(arg));
+    assert(ret == 42);
+}
+
+template <class Expect, class Functor>
+constexpr void test_b34(Functor&& f) {
+    // Create the callable object.
+    typedef int TestClass::*ClassFunc;
+    ClassFunc func_ptr = &TestClass::data;
+
+    // Check that the deduced return type of invoke is what is expected.
+    typedef decltype(
+        std::invoke(func_ptr, std::forward<Functor>(f))
+    ) DeducedReturnType;
+    static_assert((std::is_same<DeducedReturnType, Expect>::value), "");
+
+    // Check that result_of_t matches Expect.
+    typedef typename std::result_of<ClassFunc&&(Functor&&)>::type
+            ResultOfReturnType;
+    static_assert((std::is_same<ResultOfReturnType, Expect>::value), "");
+
+    // Run invoke and check the return value.
+    DeducedReturnType ret =
+            std::invoke(func_ptr, std::forward<Functor>(f));
+    assert(ret == 42);
+}
+
+template <class Expect, class Functor>
+constexpr void test_b5(Functor&& f) {
+    NonCopyable arg;
+
+    // Check that the deduced return type of invoke is what is expected.
+    typedef decltype(
+        std::invoke(std::forward<Functor>(f), std::move(arg))
+    ) DeducedReturnType;
+    static_assert((std::is_same<DeducedReturnType, Expect>::value), "");
+
+    // Check that result_of_t matches Expect.
+    typedef typename std::result_of<Functor&&(NonCopyable&&)>::type
+            ResultOfReturnType;
+    static_assert((std::is_same<ResultOfReturnType, Expect>::value), "");
+
+    // Run invoke and check the return value.
+    DeducedReturnType ret = std::invoke(std::forward<Functor>(f), std::move(arg));
+    assert(ret == 42);
+}
+
+constexpr bool bullet_one_two_tests() {
+    {
+        TestClass cl(42);
+        test_b12<int&(NonCopyable&&) &, int&>(cl);
+        test_b12<int const&(NonCopyable&&) const &, int const&>(cl);
+
+        test_b12<int&&(NonCopyable&&) &&, int&&>(std::move(cl));
+        test_b12<int const&&(NonCopyable&&) const &&, int const&&>(std::move(cl));
+    }
+    {
+        DerivedFromTestClass cl(42);
+        test_b12<int&(NonCopyable&&) &, int&>(cl);
+        test_b12<int const&(NonCopyable&&) const &, int const&>(cl);
+
+        test_b12<int&&(NonCopyable&&) &&, int&&>(std::move(cl));
+        test_b12<int const&&(NonCopyable&&) const &&, int const&&>(std::move(cl));
+    }
+    {
+        TestClass cl_obj(42);
+        std::reference_wrapper<TestClass> cl(cl_obj);
+        test_b12<int&(NonCopyable&&) &, int&>(cl);
+        test_b12<int const&(NonCopyable&&) const &, int const&>(cl);
+
+        test_b12<int&(NonCopyable&&) &, int&>(std::move(cl));
+        test_b12<int const&(NonCopyable&&) const &, int const&>(std::move(cl));
+    }
+    {
+        DerivedFromTestClass cl_obj(42);
+        std::reference_wrapper<DerivedFromTestClass> cl(cl_obj);
+        test_b12<int&(NonCopyable&&) &, int&>(cl);
+        test_b12<int const&(NonCopyable&&) const &, int const&>(cl);
+
+        test_b12<int&(NonCopyable&&) &, int&>(std::move(cl));
+        test_b12<int const&(NonCopyable&&) const &, int const&>(std::move(cl));
+    }
+    {
+        TestClass cl_obj(42);
+        TestClass *cl = &cl_obj;
+        test_b12<int&(NonCopyable&&) &, int&>(cl);
+        test_b12<int const&(NonCopyable&&) const &, int const&>(cl);
+    }
+    {
+        DerivedFromTestClass cl_obj(42);
+        DerivedFromTestClass *cl = &cl_obj;
+        test_b12<int&(NonCopyable&&) &, int&>(cl);
+        test_b12<int const&(NonCopyable&&) const &, int const&>(cl);
+    }
+    return true;
+}
+
+constexpr bool bullet_three_four_tests() {
+    {
+        typedef TestClass Fn;
+        Fn cl(42);
+        test_b34<int&>(cl);
+        test_b34<int const&>(static_cast<Fn const&>(cl));
+
+        test_b34<int&&>(static_cast<Fn &&>(cl));
+        test_b34<int const&&>(static_cast<Fn const&&>(cl));
+    }
+    {
+        typedef DerivedFromTestClass Fn;
+        Fn cl(42);
+        test_b34<int&>(cl);
+        test_b34<int const&>(static_cast<Fn const&>(cl));
+
+        test_b34<int&&>(static_cast<Fn &&>(cl));
+        test_b34<int const&&>(static_cast<Fn const&&>(cl));
+    }
+    {
+        typedef TestClass Fn;
+        Fn cl(42);
+        test_b34<int&>(std::reference_wrapper<Fn>(cl));
+        test_b34<int const&>(std::reference_wrapper<Fn const>(cl));
+    }
+    {
+        typedef DerivedFromTestClass Fn;
+        Fn cl(42);
+        test_b34<int&>(std::reference_wrapper<Fn>(cl));
+        test_b34<int const&>(std::reference_wrapper<Fn const>(cl));
+    }
+    {
+        typedef TestClass Fn;
+        Fn cl_obj(42);
+        Fn* cl = &cl_obj;
+        test_b34<int&>(cl);
+        test_b34<int const&>(static_cast<Fn const*>(cl));
+    }
+    {
+        typedef DerivedFromTestClass Fn;
+        Fn cl_obj(42);
+        Fn* cl = &cl_obj;
+        test_b34<int&>(cl);
+        test_b34<int const&>(static_cast<Fn const*>(cl));
+    }
+    return true;
+}
+
+constexpr bool bullet_five_tests() {
+    using FooType = const int&(NonCopyable&&);
+    {
+        FooType& fn = foo;
+        test_b5<const int &>(fn);
+    }
+    {
+        FooType* fn = foo;
+        test_b5<const int &>(fn);
+    }
+    {
+        typedef TestClass Fn;
+        Fn cl(42);
+        test_b5<int&>(cl);
+        test_b5<int const&>(static_cast<Fn const&>(cl));
+
+        test_b5<int&&>(static_cast<Fn &&>(cl));
+        test_b5<int const&&>(static_cast<Fn const&&>(cl));
+    }
+    return true;
+}
+
+int main(int, char**) {
+    bullet_one_two_tests();
+    bullet_three_four_tests();
+    bullet_five_tests();
+
+    static_assert(bullet_one_two_tests());
+    static_assert(bullet_three_four_tests());
+    static_assert(bullet_five_tests());
+
+    return 0;
+}

diff  --git a/libcxx/test/std/utilities/function.objects/func.memfn/member_data.pass.cpp b/libcxx/test/std/utilities/function.objects/func.memfn/member_data.pass.cpp
index 0c340072da5a..5cb4d2d28ab5 100644
--- a/libcxx/test/std/utilities/function.objects/func.memfn/member_data.pass.cpp
+++ b/libcxx/test/std/utilities/function.objects/func.memfn/member_data.pass.cpp
@@ -21,7 +21,7 @@ struct A
 };
 
 template <class F>
-void
+TEST_CONSTEXPR_CXX20 bool
 test(F f)
 {
     {
@@ -36,11 +36,16 @@ test(F f)
     const F& cf = f;
     assert(cf(ap) == f(ap));
     }
+    return true;
 }
 
 int main(int, char**)
 {
     test(std::mem_fn(&A::data_));
 
-  return 0;
+#if TEST_STD_VER >= 20
+    static_assert(test(std::mem_fn(&A::data_)));
+#endif
+
+    return 0;
 }

diff  --git a/libcxx/test/std/utilities/function.objects/func.memfn/member_function.pass.cpp b/libcxx/test/std/utilities/function.objects/func.memfn/member_function.pass.cpp
index a271c067008b..88d4108e10ac 100644
--- a/libcxx/test/std/utilities/function.objects/func.memfn/member_function.pass.cpp
+++ b/libcxx/test/std/utilities/function.objects/func.memfn/member_function.pass.cpp
@@ -18,13 +18,13 @@
 
 struct A
 {
-    char test0() {return 'a';}
-    char test1(int) {return 'b';}
-    char test2(int, double) {return 'c';}
+    TEST_CONSTEXPR_CXX14 char test0() {return 'a';}
+    TEST_CONSTEXPR_CXX14 char test1(int) {return 'b';}
+    TEST_CONSTEXPR_CXX14 char test2(int, double) {return 'c';}
 };
 
 template <class F>
-void
+TEST_CONSTEXPR_CXX20 bool
 test0(F f)
 {
     {
@@ -35,10 +35,11 @@ test0(F f)
     const F& cf = f;
     assert(cf(ap) == 'a');
     }
+    return true;
 }
 
 template <class F>
-void
+TEST_CONSTEXPR_CXX20 bool
 test1(F f)
 {
     {
@@ -49,10 +50,11 @@ test1(F f)
     const F& cf = f;
     assert(cf(ap, 2) == 'b');
     }
+    return true;
 }
 
 template <class F>
-void
+TEST_CONSTEXPR_CXX20 bool
 test2(F f)
 {
     {
@@ -63,6 +65,7 @@ test2(F f)
     const F& cf = f;
     assert(cf(ap, 2, 3.5) == 'c');
     }
+    return true;
 }
 
 int main(int, char**)
@@ -74,5 +77,11 @@ int main(int, char**)
     static_assert((noexcept(std::mem_fn(&A::test0))), ""); // LWG#2489
 #endif
 
-  return 0;
+#if TEST_STD_VER >= 20
+    static_assert(test0(std::mem_fn(&A::test0)));
+    static_assert(test1(std::mem_fn(&A::test1)));
+    static_assert(test2(std::mem_fn(&A::test2)));
+#endif
+
+    return 0;
 }

diff  --git a/libcxx/test/std/utilities/function.objects/func.memfn/member_function_const.pass.cpp b/libcxx/test/std/utilities/function.objects/func.memfn/member_function_const.pass.cpp
index 006a5bec2d39..057998c7e6e5 100644
--- a/libcxx/test/std/utilities/function.objects/func.memfn/member_function_const.pass.cpp
+++ b/libcxx/test/std/utilities/function.objects/func.memfn/member_function_const.pass.cpp
@@ -18,13 +18,13 @@
 
 struct A
 {
-    char test0() const {return 'a';}
-    char test1(int) const {return 'b';}
-    char test2(int, double) const {return 'c';}
+    TEST_CONSTEXPR char test0() const {return 'a';}
+    TEST_CONSTEXPR char test1(int) const {return 'b';}
+    TEST_CONSTEXPR char test2(int, double) const {return 'c';}
 };
 
 template <class F>
-void
+TEST_CONSTEXPR_CXX20 bool
 test0(F f)
 {
     {
@@ -37,10 +37,11 @@ test0(F f)
     const F& cf = f;
     assert(cf(ap) == 'a');
     }
+    return true;
 }
 
 template <class F>
-void
+TEST_CONSTEXPR_CXX20 bool
 test1(F f)
 {
     {
@@ -53,10 +54,11 @@ test1(F f)
     const F& cf = f;
     assert(cf(ap, 2) == 'b');
     }
+    return true;
 }
 
 template <class F>
-void
+TEST_CONSTEXPR_CXX20 bool
 test2(F f)
 {
     {
@@ -69,6 +71,7 @@ test2(F f)
     const F& cf = f;
     assert(cf(ap, 2, 3.5) == 'c');
     }
+    return true;
 }
 
 int main(int, char**)
@@ -77,5 +80,11 @@ int main(int, char**)
     test1(std::mem_fn(&A::test1));
     test2(std::mem_fn(&A::test2));
 
-  return 0;
+#if TEST_STD_VER >= 20
+    static_assert(test0(std::mem_fn(&A::test0)));
+    static_assert(test1(std::mem_fn(&A::test1)));
+    static_assert(test2(std::mem_fn(&A::test2)));
+#endif
+
+    return 0;
 }

diff  --git a/libcxx/test/std/utilities/function.objects/func.not_fn/not_fn.pass.cpp b/libcxx/test/std/utilities/function.objects/func.not_fn/not_fn.pass.cpp
index 75f7f9fd4f02..bb86dc9a8b6f 100644
--- a/libcxx/test/std/utilities/function.objects/func.not_fn/not_fn.pass.cpp
+++ b/libcxx/test/std/utilities/function.objects/func.not_fn/not_fn.pass.cpp
@@ -23,50 +23,50 @@
 //                       CALLABLE TEST TYPES
 ///////////////////////////////////////////////////////////////////////////////
 
-bool returns_true() { return true; }
+constexpr bool returns_true() { return true; }
 
 template <class Ret = bool>
 struct MoveOnlyCallable {
   MoveOnlyCallable(MoveOnlyCallable const&) = delete;
-  MoveOnlyCallable(MoveOnlyCallable&& other)
+  constexpr MoveOnlyCallable(MoveOnlyCallable&& other)
       : value(other.value)
   { other.value = !other.value; }
 
   template <class ...Args>
-  Ret operator()(Args&&...) { return Ret{value}; }
+  constexpr Ret operator()(Args&&...) { return Ret{value}; }
 
-  explicit MoveOnlyCallable(bool x) : value(x) {}
+  constexpr explicit MoveOnlyCallable(bool x) : value(x) {}
   Ret value;
 };
 
 template <class Ret = bool>
 struct CopyCallable {
-  CopyCallable(CopyCallable const& other)
+  constexpr CopyCallable(CopyCallable const& other)
       : value(other.value) {}
 
-  CopyCallable(CopyCallable&& other)
+  constexpr CopyCallable(CopyCallable&& other)
       : value(other.value) { other.value = !other.value; }
 
   template <class ...Args>
-  Ret operator()(Args&&...) { return Ret{value}; }
+  constexpr Ret operator()(Args&&...) { return Ret{value}; }
 
-  explicit CopyCallable(bool x) : value(x)  {}
+  constexpr explicit CopyCallable(bool x) : value(x)  {}
   Ret value;
 };
 
 
 template <class Ret = bool>
 struct ConstCallable {
-  ConstCallable(ConstCallable const& other)
+  constexpr ConstCallable(ConstCallable const& other)
       : value(other.value) {}
 
-  ConstCallable(ConstCallable&& other)
+  constexpr ConstCallable(ConstCallable&& other)
       : value(other.value) { other.value = !other.value; }
 
   template <class ...Args>
-  Ret operator()(Args&&...) const { return Ret{value}; }
+  constexpr Ret operator()(Args&&...) const { return Ret{value}; }
 
-  explicit ConstCallable(bool x) : value(x)  {}
+  constexpr explicit ConstCallable(bool x) : value(x)  {}
   Ret value;
 };
 
@@ -74,51 +74,51 @@ struct ConstCallable {
 
 template <class Ret = bool>
 struct NoExceptCallable {
-  NoExceptCallable(NoExceptCallable const& other)
+  constexpr NoExceptCallable(NoExceptCallable const& other)
       : value(other.value) {}
 
   template <class ...Args>
-  Ret operator()(Args&&...) noexcept { return Ret{value}; }
+  constexpr Ret operator()(Args&&...) noexcept { return Ret{value}; }
 
   template <class ...Args>
-  Ret operator()(Args&&...) const noexcept { return Ret{value}; }
+  constexpr Ret operator()(Args&&...) const noexcept { return Ret{value}; }
 
-  explicit NoExceptCallable(bool x) : value(x)  {}
+  constexpr explicit NoExceptCallable(bool x) : value(x)  {}
   Ret value;
 };
 
 struct CopyAssignableWrapper {
-  CopyAssignableWrapper(CopyAssignableWrapper const&) = default;
-  CopyAssignableWrapper(CopyAssignableWrapper&&) = default;
-  CopyAssignableWrapper& operator=(CopyAssignableWrapper const&) = default;
-  CopyAssignableWrapper& operator=(CopyAssignableWrapper &&) = default;
+  constexpr CopyAssignableWrapper(CopyAssignableWrapper const&) = default;
+  constexpr CopyAssignableWrapper(CopyAssignableWrapper&&) = default;
+  constexpr CopyAssignableWrapper& operator=(CopyAssignableWrapper const&) = default;
+  constexpr CopyAssignableWrapper& operator=(CopyAssignableWrapper &&) = default;
 
   template <class ...Args>
-  bool operator()(Args&&...) { return value; }
+  constexpr bool operator()(Args&&...) { return value; }
 
-  explicit CopyAssignableWrapper(bool x) : value(x) {}
+  constexpr explicit CopyAssignableWrapper(bool x) : value(x) {}
   bool value;
 };
 
 
 struct MoveAssignableWrapper {
-  MoveAssignableWrapper(MoveAssignableWrapper const&) = delete;
-  MoveAssignableWrapper(MoveAssignableWrapper&&) = default;
-  MoveAssignableWrapper& operator=(MoveAssignableWrapper const&) = delete;
-  MoveAssignableWrapper& operator=(MoveAssignableWrapper &&) = default;
+  constexpr MoveAssignableWrapper(MoveAssignableWrapper const&) = delete;
+  constexpr MoveAssignableWrapper(MoveAssignableWrapper&&) = default;
+  constexpr MoveAssignableWrapper& operator=(MoveAssignableWrapper const&) = delete;
+  constexpr MoveAssignableWrapper& operator=(MoveAssignableWrapper &&) = default;
 
   template <class ...Args>
-  bool operator()(Args&&...) { return value; }
+  constexpr bool operator()(Args&&...) { return value; }
 
-  explicit MoveAssignableWrapper(bool x) : value(x) {}
+  constexpr explicit MoveAssignableWrapper(bool x) : value(x) {}
   bool value;
 };
 
 struct MemFunCallable {
-  explicit MemFunCallable(bool x) : value(x) {}
+  constexpr explicit MemFunCallable(bool x) : value(x) {}
 
-  bool return_value() const { return value; }
-  bool return_value_nc() { return value; }
+  constexpr bool return_value() const { return value; }
+  constexpr bool return_value_nc() { return value; }
   bool value;
 };
 
@@ -210,7 +210,7 @@ struct EvilBool {
   friend struct CopyCallable<EvilBool>;
   friend struct NoExceptCallable<EvilBool>;
 
-  explicit EvilBool(bool x) : value(x) {}
+  constexpr explicit EvilBool(bool x) : value(x) {}
   EvilBool& operator=(EvilBool const& other) = default;
 
 public:
@@ -223,14 +223,14 @@ struct ExplicitBool {
   ExplicitBool(ExplicitBool const&) = default;
   ExplicitBool(ExplicitBool&&) = default;
 
-  explicit operator bool() const { return value; }
+  constexpr explicit operator bool() const { return value; }
 
 private:
   friend struct MoveOnlyCallable<ExplicitBool>;
   friend struct CopyCallable<ExplicitBool>;
 
-  explicit ExplicitBool(bool x) : value(x) {}
-  ExplicitBool& operator=(bool x) {
+  constexpr explicit ExplicitBool(bool x) : value(x) {}
+  constexpr ExplicitBool& operator=(bool x) {
       value = x;
       return *this;
   }
@@ -244,7 +244,7 @@ struct NoExceptEvilBool {
   NoExceptEvilBool(NoExceptEvilBool&&) = default;
   NoExceptEvilBool& operator=(NoExceptEvilBool const& other) = default;
 
-  explicit NoExceptEvilBool(bool x) : value(x) {}
+  constexpr explicit NoExceptEvilBool(bool x) : value(x) {}
 
   friend NoExceptEvilBool operator!(NoExceptEvilBool const& other) noexcept {
     return NoExceptEvilBool{!other.value};
@@ -255,7 +255,8 @@ struct NoExceptEvilBool {
 
 
 
-void constructor_tests()
+TEST_CONSTEXPR_CXX20
+bool constructor_tests()
 {
     {
         using T = MoveOnlyCallable<bool>;
@@ -335,6 +336,7 @@ void constructor_tests()
         assert(ret() == true);
 #endif // _LIBCPP_VERSION
     }
+    return true;
 }
 
 void return_type_tests()
@@ -369,7 +371,8 @@ void return_type_tests()
 
 // Other tests only test using objects with call operators. Test various
 // other callable types here.
-void other_callable_types_test()
+TEST_CONSTEXPR_CXX20
+bool other_callable_types_test()
 {
     { // test with function pointer
         auto ret = std::not_fn(returns_true);
@@ -408,6 +411,7 @@ void other_callable_types_test()
         assert(ret(&mt) == false);
         assert(ret(&mf) == true);
     }
+    return true;
 }
 
 void throws_in_constructor_test()
@@ -439,7 +443,8 @@ void throws_in_constructor_test()
 #endif
 }
 
-void call_operator_sfinae_test() {
+TEST_CONSTEXPR_CXX20
+bool call_operator_sfinae_test() {
     { // wrong number of arguments
         using T = decltype(std::not_fn(returns_true));
         static_assert(std::is_invocable<T>::value, ""); // callable only with no args
@@ -463,9 +468,11 @@ void call_operator_sfinae_test() {
         static_assert(std::is_invocable<T, bool>::value, "");
         static_assert(!std::is_invocable<T, std::string>::value, "");
     }
+    return true;
 }
 
-void call_operator_forwarding_test()
+TEST_CONSTEXPR_CXX20
+bool call_operator_forwarding_test()
 {
     using Fn = ForwardingCallObject;
     Fn::State st;
@@ -538,20 +545,23 @@ void call_operator_forwarding_test()
         assert(st.check_call<int&&>(CT_Const | CT_RValue));
     }
     { // test multi arg
+        using String = const char *;
         const double y = 3.14;
-        std::string s = "abc";
-        obj(42, std::move(y), s, std::string{"foo"});
-        assert((st.check_call<int&&, const double&&, std::string&, std::string&&>(CT_NonConst | CT_LValue)));
-        std::move(obj)(42, std::move(y), s, std::string{"foo"});
-        assert((st.check_call<int&&, const double&&, std::string&, std::string&&>(CT_NonConst | CT_RValue)));
-        c_obj(42, std::move(y), s, std::string{"foo"});
-        assert((st.check_call<int&&, const double&&, std::string&, std::string&&>(CT_Const  | CT_LValue)));
-        std::move(c_obj)(42, std::move(y), s, std::string{"foo"});
-        assert((st.check_call<int&&, const double&&, std::string&, std::string&&>(CT_Const  | CT_RValue)));
+        String s = "abc";
+        obj(42, std::move(y), s, String{"foo"});
+        assert((st.check_call<int&&, const double&&, String&, String&&>(CT_NonConst | CT_LValue)));
+        std::move(obj)(42, std::move(y), s, String{"foo"});
+        assert((st.check_call<int&&, const double&&, String&, String&&>(CT_NonConst | CT_RValue)));
+        c_obj(42, std::move(y), s, String{"foo"});
+        assert((st.check_call<int&&, const double&&, String&, String&&>(CT_Const  | CT_LValue)));
+        std::move(c_obj)(42, std::move(y), s, String{"foo"});
+        assert((st.check_call<int&&, const double&&, String&, String&&>(CT_Const  | CT_RValue)));
     }
+    return true;
 }
 
-void call_operator_noexcept_test()
+TEST_CONSTEXPR_CXX20
+bool call_operator_noexcept_test()
 {
     {
         using T = ConstCallable<bool>;
@@ -589,19 +599,22 @@ void call_operator_noexcept_test()
         auto const& cret = ret;
         static_assert(!noexcept(cret()), "call should not be noexcept");
     }
+    return true;
 }
 
-void test_lwg2767() {
+TEST_CONSTEXPR_CXX20
+bool test_lwg2767() {
     // See https://cplusplus.github.io/LWG/lwg-defects.html#2767
     struct Abstract { virtual void f() const = 0; };
     struct Derived : public Abstract { void f() const {} };
-    struct F { bool operator()(Abstract&&) { return false; } };
+    struct F { constexpr bool operator()(Abstract&&) { return false; } };
     {
         Derived d;
         Abstract &a = d;
         bool b = std::not_fn(F{})(std::move(a));
         assert(b);
     }
+    return true;
 }
 
 int main(int, char**)
@@ -615,5 +628,14 @@ int main(int, char**)
     call_operator_noexcept_test();
     test_lwg2767();
 
-  return 0;
+#if TEST_STD_VER >= 20
+    static_assert(constructor_tests());
+    static_assert(other_callable_types_test());
+    static_assert(call_operator_sfinae_test()); // somewhat of an extension
+    static_assert(call_operator_forwarding_test());
+    static_assert(call_operator_noexcept_test());
+    static_assert(test_lwg2767());
+#endif
+
+    return 0;
 }

diff  --git a/libcxx/test/std/utilities/function.objects/func.search/func.search.default/default.pass.cpp b/libcxx/test/std/utilities/function.objects/func.search/func.search.default/default.pass.cpp
index 04c2de6bda50..9c51b3ac39f3 100644
--- a/libcxx/test/std/utilities/function.objects/func.search/func.search.default/default.pass.cpp
+++ b/libcxx/test/std/utilities/function.objects/func.search/func.search.default/default.pass.cpp
@@ -39,14 +39,15 @@
 #include "test_iterators.h"
 
 template <typename Iter1, typename Iter2>
+TEST_CONSTEXPR_CXX20
 void do_search(Iter1 b1, Iter1 e1, Iter2 b2, Iter2 e2, Iter1 result) {
     std::default_searcher<Iter2> s{b2, e2};
     assert(result == std::search(b1, e1, s));
 }
 
 template <class Iter1, class Iter2>
-void
-test()
+TEST_CONSTEXPR_CXX20
+bool test()
 {
     int ia[] = {0, 1, 2, 3, 4, 5};
     const unsigned sa = sizeof(ia)/sizeof(ia[0]);
@@ -81,6 +82,8 @@ test()
     int ik[] = {0, 0, 0, 0, 1, 1, 1, 1, 0, 0};
     const unsigned sk = sizeof(ik)/sizeof(ik[0]);
     do_search(Iter1(ij), Iter1(ij+sj), Iter2(ik), Iter2(ik+sk), Iter1(ij+6));
+
+    return true;
 }
 
 int main(int, char**) {
@@ -94,5 +97,17 @@ int main(int, char**) {
     test<random_access_iterator<const int*>, bidirectional_iterator<const int*> >();
     test<random_access_iterator<const int*>, random_access_iterator<const int*> >();
 
-  return 0;
+#if TEST_STD_VER >= 20
+    static_assert(test<forward_iterator<const int*>, forward_iterator<const int*>>());
+    static_assert(test<forward_iterator<const int*>, bidirectional_iterator<const int*>>());
+    static_assert(test<forward_iterator<const int*>, random_access_iterator<const int*>>());
+    static_assert(test<bidirectional_iterator<const int*>, forward_iterator<const int*>>());
+    static_assert(test<bidirectional_iterator<const int*>, bidirectional_iterator<const int*>>());
+    static_assert(test<bidirectional_iterator<const int*>, random_access_iterator<const int*>>());
+    static_assert(test<random_access_iterator<const int*>, forward_iterator<const int*>>());
+    static_assert(test<random_access_iterator<const int*>, bidirectional_iterator<const int*>>());
+    static_assert(test<random_access_iterator<const int*>, random_access_iterator<const int*>>());
+#endif
+
+    return 0;
 }

diff  --git a/libcxx/test/std/utilities/function.objects/func.search/func.search.default/default.pred.pass.cpp b/libcxx/test/std/utilities/function.objects/func.search/func.search.default/default.pred.pass.cpp
index 6f3bdb5dfbae..bc9ba2f860b4 100644
--- a/libcxx/test/std/utilities/function.objects/func.search/func.search.default/default.pred.pass.cpp
+++ b/libcxx/test/std/utilities/function.objects/func.search/func.search.default/default.pred.pass.cpp
@@ -40,54 +40,59 @@
 
 struct count_equal
 {
-    static unsigned count;
+    unsigned *count;
+
     template <class T>
-    bool operator()(const T& x, const T& y) const
-        {++count; return x == y;}
+    TEST_CONSTEXPR_CXX14 bool operator()(const T& x, const T& y) const
+        {++*count; return x == y;}
 };
 
-unsigned count_equal::count = 0;
-
 template <typename Iter1, typename Iter2>
-void do_search(Iter1 b1, Iter1 e1, Iter2 b2, Iter2 e2, Iter1 result, unsigned max_count) {
-    std::default_searcher<Iter2, count_equal> s{b2, e2};
-    count_equal::count = 0;
+TEST_CONSTEXPR_CXX20
+void do_search(Iter1 b1, Iter1 e1, Iter2 b2, Iter2 e2, Iter1 result) {
+    unsigned count = 0;
+    std::default_searcher<Iter2, count_equal> s{b2, e2, count_equal{&count}};
     assert(result == std::search(b1, e1, s));
-    assert(count_equal::count <= max_count);
+    auto d1 = std::distance(b1, e1);
+    auto d2 = std::distance(b2, e2);
+    assert((count >= 1) || (d2 == 0) || (d1 < d2));
+    assert((d1 < d2) || count <= d1 * (d1 - d2 + 1));
 }
 
 template <class Iter1, class Iter2>
-void
-test()
+TEST_CONSTEXPR_CXX20
+bool test()
 {
     int ia[] = {0, 1, 2, 3, 4, 5};
     const unsigned sa = sizeof(ia)/sizeof(ia[0]);
-    do_search(Iter1(ia), Iter1(ia+sa),   Iter2(ia),      Iter2(ia),    Iter1(ia),      0);
-    do_search(Iter1(ia), Iter1(ia+sa),   Iter2(ia),      Iter2(ia+1),  Iter1(ia),      sa);
-    do_search(Iter1(ia), Iter1(ia+sa),   Iter2(ia+1),    Iter2(ia+2),  Iter1(ia+1),    sa);
-    do_search(Iter1(ia), Iter1(ia+sa),   Iter2(ia+2),    Iter2(ia+2),  Iter1(ia),      0);
-    do_search(Iter1(ia), Iter1(ia+sa),   Iter2(ia+2),    Iter2(ia+3),  Iter1(ia+2),    sa);
-    do_search(Iter1(ia), Iter1(ia+sa),   Iter2(ia+2),    Iter2(ia+3),  Iter1(ia+2),    sa);
-    do_search(Iter1(ia), Iter1(ia),      Iter2(ia+2),    Iter2(ia+3),  Iter1(ia),      0);
-    do_search(Iter1(ia), Iter1(ia+sa),   Iter2(ia+sa-1), Iter2(ia+sa), Iter1(ia+sa-1), sa);
-    do_search(Iter1(ia), Iter1(ia+sa),   Iter2(ia+sa-3), Iter2(ia+sa), Iter1(ia+sa-3), 3*sa);
-    do_search(Iter1(ia), Iter1(ia+sa),   Iter2(ia),      Iter2(ia+sa), Iter1(ia),      sa*sa);
-    do_search(Iter1(ia), Iter1(ia+sa-1), Iter2(ia),      Iter2(ia+sa), Iter1(ia+sa-1), (sa-1)*sa);
-    do_search(Iter1(ia), Iter1(ia+1),    Iter2(ia),      Iter2(ia+sa), Iter1(ia+1),    sa);
+    do_search(Iter1(ia), Iter1(ia+sa),   Iter2(ia),      Iter2(ia),    Iter1(ia));
+    do_search(Iter1(ia), Iter1(ia+sa),   Iter2(ia),      Iter2(ia+1),  Iter1(ia));
+    do_search(Iter1(ia), Iter1(ia+sa),   Iter2(ia+1),    Iter2(ia+2),  Iter1(ia+1));
+    do_search(Iter1(ia), Iter1(ia+sa),   Iter2(ia+2),    Iter2(ia+2),  Iter1(ia));
+    do_search(Iter1(ia), Iter1(ia+sa),   Iter2(ia+2),    Iter2(ia+3),  Iter1(ia+2));
+    do_search(Iter1(ia), Iter1(ia+sa),   Iter2(ia+2),    Iter2(ia+3),  Iter1(ia+2));
+    do_search(Iter1(ia), Iter1(ia),      Iter2(ia+2),    Iter2(ia+3),  Iter1(ia));
+    do_search(Iter1(ia), Iter1(ia+sa),   Iter2(ia+sa-1), Iter2(ia+sa), Iter1(ia+sa-1));
+    do_search(Iter1(ia), Iter1(ia+sa),   Iter2(ia+sa-3), Iter2(ia+sa), Iter1(ia+sa-3));
+    do_search(Iter1(ia), Iter1(ia+sa),   Iter2(ia),      Iter2(ia+sa), Iter1(ia));
+    do_search(Iter1(ia), Iter1(ia+sa-1), Iter2(ia),      Iter2(ia+sa), Iter1(ia+sa-1));
+    do_search(Iter1(ia), Iter1(ia+1),    Iter2(ia),      Iter2(ia+sa), Iter1(ia+1));
     int ib[] = {0, 1, 2, 0, 1, 2, 3, 0, 1, 2, 3, 4};
     const unsigned sb = sizeof(ib)/sizeof(ib[0]);
     int ic[] = {1};
-    do_search(Iter1(ib), Iter1(ib+sb), Iter2(ic), Iter2(ic+1), Iter1(ib+1), sb);
+    do_search(Iter1(ib), Iter1(ib+sb), Iter2(ic), Iter2(ic+1), Iter1(ib+1));
     int id[] = {1, 2};
-    do_search(Iter1(ib), Iter1(ib+sb), Iter2(id), Iter2(id+2), Iter1(ib+1), sb*2);
+    do_search(Iter1(ib), Iter1(ib+sb), Iter2(id), Iter2(id+2), Iter1(ib+1));
     int ie[] = {1, 2, 3};
-    do_search(Iter1(ib), Iter1(ib+sb), Iter2(ie), Iter2(ie+3), Iter1(ib+4), sb*3);
+    do_search(Iter1(ib), Iter1(ib+sb), Iter2(ie), Iter2(ie+3), Iter1(ib+4));
     int ig[] = {1, 2, 3, 4};
-    do_search(Iter1(ib), Iter1(ib+sb), Iter2(ig), Iter2(ig+4), Iter1(ib+8), sb*4);
+    do_search(Iter1(ib), Iter1(ib+sb), Iter2(ig), Iter2(ig+4), Iter1(ib+8));
     int ih[] = {0, 1, 1, 1, 1, 2, 3, 0, 1, 2, 3, 4};
     const unsigned sh = sizeof(ih)/sizeof(ih[0]);
     int ii[] = {1, 1, 2};
-    do_search(Iter1(ih), Iter1(ih+sh), Iter2(ii), Iter2(ii+3), Iter1(ih+3),  sh*3);
+    do_search(Iter1(ih), Iter1(ih+sh), Iter2(ii), Iter2(ii+3), Iter1(ih+3));
+
+    return true;
 }
 
 int main(int, char**) {
@@ -101,5 +106,17 @@ int main(int, char**) {
     test<random_access_iterator<const int*>, bidirectional_iterator<const int*> >();
     test<random_access_iterator<const int*>, random_access_iterator<const int*> >();
 
-  return 0;
+#if TEST_STD_VER >= 20
+    static_assert(test<forward_iterator<const int*>, forward_iterator<const int*>>());
+    static_assert(test<forward_iterator<const int*>, bidirectional_iterator<const int*>>());
+    static_assert(test<forward_iterator<const int*>, random_access_iterator<const int*>>());
+    static_assert(test<bidirectional_iterator<const int*>, forward_iterator<const int*>>());
+    static_assert(test<bidirectional_iterator<const int*>, bidirectional_iterator<const int*>>());
+    static_assert(test<bidirectional_iterator<const int*>, random_access_iterator<const int*>>());
+    static_assert(test<random_access_iterator<const int*>, forward_iterator<const int*>>());
+    static_assert(test<random_access_iterator<const int*>, bidirectional_iterator<const int*>>());
+    static_assert(test<random_access_iterator<const int*>, random_access_iterator<const int*>>());
+#endif
+
+    return 0;
 }

diff  --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py
index 5010c080c759..091fea431384 100755
--- a/libcxx/utils/generate_feature_test_macro_components.py
+++ b/libcxx/utils/generate_feature_test_macro_components.py
@@ -369,10 +369,9 @@ def add_version_header(tc):
     "headers": ["algorithm"],
     "unimplemented": True,
   }, {
-    "name": "__cpp_lib_constexpr_misc",
-    "values": { "c++2a": int(201811) },
-    "headers": ["array", "functional", "iterator", "string_view", "tuple", "utility"],
-    "unimplemented": True,
+    "name": "__cpp_lib_constexpr_functional",
+    "values": { "c++2a": int(201907) },
+    "headers": ["functional"],
   }, {
     "name": "__cpp_lib_constexpr_numeric",
     "values": { "c++2a": int(201911) },


        


More information about the llvm-branch-commits mailing list