From 1fa58ff86324a7ffa2d4f258ed16f5aaf8849620 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 29 Feb 2024 16:27:27 -0800 Subject: [PATCH 1/4] Overhaul FDIS citation and extend test coverage for `std::function` PMFs/PMDs. FDIS citations were so old, they escaped our scans for outdated WPs. We don't need to quote `INVOKE`'s Standardese at length, we just need to summarize it. It used to be really confusing, now it's easy mode. A couple of things have changed: derived values are now covered by the Standardese, and `reference_wrapper` support was added. This is tested elsewhere, e.g. in `Dev11_0535636_functional_overhaul`, but we can easily add comprehensive test coverage here. I chose `f1x` and `g1x` to avoid renumbering everything. --- .../test.cpp | 80 ++++++++----------- 1 file changed, 33 insertions(+), 47 deletions(-) diff --git a/tests/std/tests/Dev09_174589_tr1_function_storing_pmf_called_with_reference_or_pointer/test.cpp b/tests/std/tests/Dev09_174589_tr1_function_storing_pmf_called_with_reference_or_pointer/test.cpp index a3c65d78f80..0c8b42eb050 100644 --- a/tests/std/tests/Dev09_174589_tr1_function_storing_pmf_called_with_reference_or_pointer/test.cpp +++ b/tests/std/tests/Dev09_174589_tr1_function_storing_pmf_called_with_reference_or_pointer/test.cpp @@ -30,34 +30,8 @@ void test_orig() { // DevDiv-294051 ": std::function has lost the ability to invoke PMFs/PMDs on various things" -// FDIS 20.8.11.2 [func.wrap.func] specifies: -// template class function -// /7 says: -// template function(F f); -// Requires: F shall be CopyConstructible. f shall be Callable (20.8.11.2) for -// argument types ArgTypes and return type R. The copy constructor and -// destructor of A shall not throw exceptions. -// /2 says: -// A callable object f of type F is Callable for argument types ArgTypes and -// return type R if the expression INVOKE(f, declval()..., R), -// considered as an unevaluated operand (Clause 5), is well formed (20.8.2). -// 20.8.2 [func.require]/1-2 says: -// Define INVOKE(f, t1, t2, ..., tN) as follows: -// - (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; -// - ((*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; -// - 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; -// - (*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; -// - f(t1, t2, ..., tN) in all other cases. -// Define INVOKE(f, t1, t2, ..., tN, R) as INVOKE(f, t1, t2, ..., tN) implicitly converted to R. - -// Therefore, std::function must be able to invoke PMFs/PMDs -// on values, references, derived references, raw pointers, and smart pointers. +// N4971 [func.require] says that std::function must be able to invoke PMFs/PMDs +// on values, references, raw pointers, smart pointers, and reference_wrappers - all handling base/derived cases. struct B { int func(int i) { @@ -76,17 +50,21 @@ void test_DevDiv_294051() { b->data = 220; x->data = 330; - function f1 = &B::func; - function f2 = &B::func; - function f3 = &B::func; - function f4 = &B::func; - function f5 = &B::func; - function, int)> f6 = &B::func; - function, int)> f7 = &B::func; - function&, int)> f8 = &B::func; - function&, int)> f9 = &B::func; + function f1 = &B::func; + function f1x = &B::func; + function f2 = &B::func; + function f3 = &B::func; + function f4 = &B::func; + function f5 = &B::func; + function, int)> f6 = &B::func; + function, int)> f7 = &B::func; + function&, int)> f8 = &B::func; + function&, int)> f9 = &B::func; + function, int)> f10 = &B::func; + function, int)> f11 = &B::func; assert(f1(*b, 1000) == 1225); + assert(f1x(*x, 1000) == 1335); assert(f2(*b, 2000) == 2225); assert(f3(*x, 3000) == 3335); assert(f4(b.get(), 4000) == 4225); @@ -95,18 +73,24 @@ void test_DevDiv_294051() { assert(f7(x, 7000) == 7335); assert(f8(b, 8000) == 8225); assert(f9(x, 9000) == 9335); - - function g1 = &B::data; - function g2 = &B::data; - function g3 = &B::data; - function g4 = &B::data; - function g5 = &B::data; - function)> g6 = &B::data; - function)> g7 = &B::data; - function&)> g8 = &B::data; - function&)> g9 = &B::data; + assert(f10(ref(*b), 10000) == 10225); + assert(f11(ref(*x), 11000) == 11335); + + function g1 = &B::data; + function g1x = &B::data; + function g2 = &B::data; + function g3 = &B::data; + function g4 = &B::data; + function g5 = &B::data; + function)> g6 = &B::data; + function)> g7 = &B::data; + function&)> g8 = &B::data; + function&)> g9 = &B::data; + function)> g10 = &B::data; + function)> g11 = &B::data; assert(g1(*b) == 220); + assert(g1x(*x) == 330); assert(g2(*b) == 220); assert(g3(*x) == 330); assert(g4(b.get()) == 220); @@ -115,6 +99,8 @@ void test_DevDiv_294051() { assert(g7(x) == 330); assert(g8(b) == 220); assert(g9(x) == 330); + assert(g10(ref(*b)) == 220); + assert(g11(ref(*x)) == 330); } From a5ddeab61ca93a3fca501ce2e669adcd54abf480 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 29 Feb 2024 16:51:05 -0800 Subject: [PATCH 2/4] Update FDIS citations and add test coverage for `mem_fn` typedefs. These typedefs were deprecated in C++17 and removed in C++20, so I'm citing N4659, the C++17 WP. We were also missing test coverage for when `mem_fn` provides only `result_type`. Even though this is deprecated/removed, we may as well be comprehensive. --- .../test.cpp | 33 ++++++++++++++++--- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/tests/std/tests/Dev09_172497_tr1_mem_fn_const_correctness/test.cpp b/tests/std/tests/Dev09_172497_tr1_mem_fn_const_correctness/test.cpp index 31e85b3c163..d9eb0887772 100644 --- a/tests/std/tests/Dev09_172497_tr1_mem_fn_const_correctness/test.cpp +++ b/tests/std/tests/Dev09_172497_tr1_mem_fn_const_correctness/test.cpp @@ -37,10 +37,23 @@ struct Cat { double purr_cv(int) const volatile { return 22.2; } + + long double hiss(int, int) { + return 33.3l; + } + long double hiss_c(int, int) const { + return 33.3l; + } + long double hiss_v(int, int) volatile { + return 33.3l; + } + long double hiss_cv(int, int) const volatile { + return 33.3l; + } }; -// FDIS 20.8.10 [func.memfn]/2: "The simple call wrapper shall define two nested types named -// argument_type and result_type as synonyms for cv T* and Ret, respectively, when pm is a pointer to +// N4659 [depr.func.adaptor.typedefs]/10: "The simple call wrapper returned from a call to mem_fn(pm) shall define two +// nested types named argument_type and result_type as synonyms for cv T* and Ret, respectively, when pm is a pointer to // member function with cv-qualifier cv and taking no arguments, where Ret is pm's return type." template void test_unary(F) { @@ -48,8 +61,8 @@ void test_unary(F) { STATIC_ASSERT(is_same_v); } -// FDIS 20.8.10 [func.memfn]/3: "The simple call wrapper shall define three nested types named -// first_argument_type, second_argument_type, and result_type as synonyms for cv T*, T1, and Ret, +// N4659 [depr.func.adaptor.typedefs]/11: "The simple call wrapper returned from a call to mem_fn(pm) shall define three +// nested types named first_argument_type, second_argument_type, and result_type as synonyms for cv T*, T1, and Ret, // respectively, when pm is a pointer to member function with cv-qualifier cv and taking one argument // of type T1, where Ret is pm's return type." template @@ -59,6 +72,13 @@ void test_binary(F) { STATIC_ASSERT(is_same_v); } +// N4659 [depr.func.adaptor.typedefs]/9: "The simple call wrapper returned from a call to mem_fn(pm) shall have a +// nested type result_type that is a synonym for the return type of pm when pm is a pointer to member function." +template +void test_ternary(F) { + STATIC_ASSERT(is_same_v); +} + int main() { test_unary(mem_fn(&Cat::meow)); test_unary(mem_fn(&Cat::meow_c)); @@ -69,4 +89,9 @@ int main() { test_binary(mem_fn(&Cat::purr_c)); test_binary(mem_fn(&Cat::purr_v)); test_binary(mem_fn(&Cat::purr_cv)); + + test_ternary(mem_fn(&Cat::hiss)); + test_ternary(mem_fn(&Cat::hiss_c)); + test_ternary(mem_fn(&Cat::hiss_v)); + test_ternary(mem_fn(&Cat::hiss_cv)); } From 761f7191d4bcf9975670ebc9e63fbded9ee7d0ee Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Sat, 2 Mar 2024 15:28:42 -0800 Subject: [PATCH 3/4] P0088R3_variant: Activate EDG test coverage. --- tests/std/tests/P0088R3_variant/test.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/std/tests/P0088R3_variant/test.cpp b/tests/std/tests/P0088R3_variant/test.cpp index fb52581cb74..ca7c37196d0 100644 --- a/tests/std/tests/P0088R3_variant/test.cpp +++ b/tests/std/tests/P0088R3_variant/test.cpp @@ -6114,7 +6114,7 @@ int run_test() #include "variant_test_helpers.h" namespace visit { -#if _HAS_CXX20 && !defined(__EDG__) && !defined(TEST_PERMISSIVE) +#if _HAS_CXX20 && !defined(TEST_PERMISSIVE) void test_call_operator_forwarding() { using Fn = ForwardingCallObject; Fn obj{}; @@ -6563,7 +6563,7 @@ int run_test() { #include "variant_test_helpers.h" namespace visit::return_type { -#if _HAS_CXX20 && !defined(__EDG__) && !defined(TEST_PERMISSIVE) +#if _HAS_CXX20 && !defined(TEST_PERMISSIVE) template void test_call_operator_forwarding() { using Fn = ForwardingCallObject; From 0c1e230ec166d129845010386301c1c9d964cd10 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 29 Feb 2024 17:03:48 -0800 Subject: [PATCH 4/4] In benchmarks/inc, include `` and qualify `std::`. --- benchmarks/inc/utility.hpp | 2 +- benchmarks/inc/xoshiro.hpp | 17 +++++++++-------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/benchmarks/inc/utility.hpp b/benchmarks/inc/utility.hpp index b74b4078ca9..ecfe0890a16 100644 --- a/benchmarks/inc/utility.hpp +++ b/benchmarks/inc/utility.hpp @@ -14,7 +14,7 @@ template std::vector random_vector(size_t n) { std::random_device rd; - std::uniform_int_distribution id64; + std::uniform_int_distribution id64; xoshiro256ss prng{id64(rd), id64(rd), id64(rd), id64(rd)}; std::vector res(n); diff --git a/benchmarks/inc/xoshiro.hpp b/benchmarks/inc/xoshiro.hpp index 82d4856ef52..3a302105da0 100644 --- a/benchmarks/inc/xoshiro.hpp +++ b/benchmarks/inc/xoshiro.hpp @@ -10,16 +10,17 @@ SPDX-License-Identifier: CC0-1.0 */ #pragma once #include -#include +#include struct xoshiro256ss { xoshiro256ss() = delete; - xoshiro256ss(uint64_t s0, uint64_t s1, uint64_t s2, uint64_t s3) : s0_(s0), s1_(s1), s2_(s2), s3_(s3) {} + xoshiro256ss(std::uint64_t s0, std::uint64_t s1, std::uint64_t s2, std::uint64_t s3) + : s0_(s0), s1_(s1), s2_(s2), s3_(s3) {} - uint64_t next() { + std::uint64_t next() { auto result = std::rotl(s1_ * 5, 7) * 9; - const uint64_t t = s1_ << 17; + const std::uint64_t t = s1_ << 17; s2_ ^= s0_; s3_ ^= s1_; @@ -34,8 +35,8 @@ struct xoshiro256ss { } private: - uint64_t s0_; - uint64_t s1_; - uint64_t s2_; - uint64_t s3_; + std::uint64_t s0_; + std::uint64_t s1_; + std::uint64_t s2_; + std::uint64_t s3_; };