Skip to content

Commit 52b44d9

Browse files
mattkretzTomasz Kamiński
andcommitted
libstdc++: Remove non_type and replace it with constant_wrapper in function_ref
This implements P3948R1: constant_wrapper is the only tool needed for passing constant expressions via function arguments. This changes function_ref from nontype_t to constant_wrapper and implements the ambiguity check (static_asert in function_ref from constant_wrapper constructor). In addition to P3948R1 this also includes the (forgotten) deduction guide changes suggested in the draft PR [1]. [1] cplusplus/draft#8878 libstdc++-v3/ChangeLog: * include/bits/funcref_impl.h (function_ref::function_ref): Change nontype_t parameter to constant_wrapper, and adjust accordingly. Add static_assert detecting ambigous semantics. (function_ref::operator=): Detect constant_wrapper rather than nontype_t. * include/bits/funcwrap.h (function_ref): Change nontype_t parameter to constant_wrapper in deduction guides. * include/bits/utility.h (std::nontype_t, std::nontype) (std::__is_nontype_v): Remove. (std::__is_constant_wrapper_v): Define. * src/c++23/std.cc.in (std::nontype_t, std::nontype): Remove exports. * testsuite/20_util/function_ref/cw_cons_neg.cc: New tests for ambiguity check. * testsuite/20_util/function_ref/assign.cc: Replace nontype_t with constant_wrapper and nontype with std::cw. * testsuite/20_util/function_ref/call.cc: Likewise. * testsuite/20_util/function_ref/cons.cc: Likewise. * testsuite/20_util/function_ref/cons_neg.cc: Likewise. * testsuite/20_util/function_ref/dangling.cc: Likewise. * testsuite/20_util/function_ref/deduction.cc: Likewise. * testsuite/20_util/function_ref/mutation.cc: Likewise. Co-authored-by: Tomasz Kamiński <tkaminsk@redhat.com> Reviewed-by: Jonathan Wakely <jwakely@redhat.com> Signed-off-by: Matthias Kretz <m.kretz@gsi.de> Signed-off-by: Tomasz Kamiński <tkaminsk@redhat.com>
1 parent 5196331 commit 52b44d9

12 files changed

Lines changed: 185 additions & 163 deletions

File tree

libstdc++-v3/include/bits/funcref_impl.h

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -129,12 +129,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
129129
// _GLIBCXX_RESOLVE_LIB_DEFECTS
130130
// 4256. Incorrect constrains for function_ref constructors from nontype
131131
/// Target object is __fn. There is no bound object.
132-
template<auto __fn>
133-
requires __is_invocable_using<const decltype(__fn)&>
132+
template<auto __cwfn, typename _Fn>
133+
requires __is_invocable_using<const _Fn&>
134134
constexpr
135-
function_ref(nontype_t<__fn>) noexcept
135+
function_ref(constant_wrapper<__cwfn, _Fn>) noexcept
136136
{
137-
using _Fn = remove_cv_t<decltype(__fn)>;
137+
constexpr const _Fn& __fn = constant_wrapper<__cwfn, _Fn>::value;
138+
if constexpr (sizeof...(_ArgTypes) > 0)
139+
if constexpr ((... && _ConstExprParam<remove_cvref_t<_ArgTypes>>))
140+
static_assert(!requires {
141+
typename constant_wrapper<
142+
std::__invoke(__fn, remove_cvref_t<_ArgTypes>::value...)>;
143+
}, "cw<fn>(args...) should be equivalent to fn(args...)");
144+
138145
if constexpr (is_pointer_v<_Fn> || is_member_pointer_v<_Fn>)
139146
static_assert(__fn != nullptr);
140147

@@ -144,13 +151,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
144151

145152
/// Target object is equivalent to std::bind_front<_fn>(std::ref(__ref)).
146153
/// Bound object is object referenced by second parameter.
147-
template<auto __fn, typename _Up, typename _Td = remove_reference_t<_Up>>
154+
template<auto __cwfn, typename _Fn, typename _Up,
155+
typename _Td = remove_reference_t<_Up>>
148156
requires (!is_rvalue_reference_v<_Up&&>)
149-
&& __is_invocable_using<const decltype(__fn)&, _Td _GLIBCXX_MOF_CV&>
157+
&& __is_invocable_using<const _Fn&, _Td _GLIBCXX_MOF_CV&>
150158
constexpr
151-
function_ref(nontype_t<__fn>, _Up&& __ref) noexcept
159+
function_ref(constant_wrapper<__cwfn, _Fn>, _Up&& __ref) noexcept
152160
{
153-
using _Fn = remove_cv_t<decltype(__fn)>;
161+
constexpr const _Fn& __fn = constant_wrapper<__cwfn, _Fn>::value;
154162
if constexpr (is_pointer_v<_Fn> || is_member_pointer_v<_Fn>)
155163
static_assert(__fn != nullptr);
156164

@@ -166,12 +174,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
166174

167175
/// Target object is equivalent to std::bind_front<_fn>(__ptr).
168176
/// Bound object is object pointed by second parameter (if any).
169-
template<auto __fn, typename _Td>
170-
requires __is_invocable_using<const decltype(__fn)&, _Td _GLIBCXX_MOF_CV*>
177+
template< auto __cwfn, typename _Fn, typename _Td>
178+
requires __is_invocable_using<const _Fn&, _Td _GLIBCXX_MOF_CV*>
171179
constexpr
172-
function_ref(nontype_t<__fn>, _Td _GLIBCXX_MOF_CV* __ptr) noexcept
180+
function_ref(constant_wrapper<__cwfn, _Fn>, _Td _GLIBCXX_MOF_CV* __ptr) noexcept
173181
{
174-
using _Fn = remove_cv_t<decltype(__fn)>;
182+
constexpr const _Fn& __fn = constant_wrapper<__cwfn, _Fn>::value;
175183
if constexpr (is_pointer_v<_Fn> || is_member_pointer_v<_Fn>)
176184
static_assert(__fn != nullptr);
177185
if constexpr (is_member_pointer_v<_Fn>)
@@ -182,8 +190,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
182190
}
183191

184192
template<typename _Tp>
185-
requires (!is_same_v<_Tp, function_ref>)
186-
&& (!is_pointer_v<_Tp>) && (!__is_nontype_v<_Tp>)
193+
requires (!is_same_v<_Tp, function_ref>) && (!is_pointer_v<_Tp>)
194+
&& (!__is_constant_wrapper_v<_Tp>)
187195
function_ref&
188196
operator=(_Tp) = delete;
189197

libstdc++-v3/include/bits/funcwrap.h

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -573,15 +573,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
573573
requires is_function_v<_Fn>
574574
function_ref(_Fn*) -> function_ref<_Fn>;
575575

576-
template<auto __f, class _Fn = remove_pointer_t<decltype(__f)>>
577-
requires is_function_v<_Fn>
578-
function_ref(nontype_t<__f>) -> function_ref<_Fn>;
576+
template<auto __cwfn, typename _Fn>
577+
requires is_function_v<remove_pointer_t<_Fn>>
578+
function_ref(constant_wrapper<__cwfn, _Fn>)
579+
-> function_ref<remove_pointer_t<_Fn>>;
579580

580-
template<auto __f, typename _Tp,
581+
template<auto __cwfn, typename _Fn, typename _Tp,
581582
typename _SignaturePtr =
582-
decltype(__polyfunc::__deduce_funcref<decltype(__f), _Tp&>())>
583+
decltype(__polyfunc::__deduce_funcref<_Fn, _Tp&>())>
583584
requires (!is_void_v<_SignaturePtr>)
584-
function_ref(nontype_t<__f>, _Tp&&)
585+
function_ref(constant_wrapper<__cwfn, _Fn>, _Tp&&)
585586
-> function_ref<remove_pointer_t<_SignaturePtr>>;
586587

587588
#endif // __glibcxx_function_ref

libstdc++-v3/include/bits/utility.h

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -458,6 +458,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
458458
{ return value; }
459459
};
460460

461+
template<typename>
462+
constexpr bool __is_constant_wrapper_v = false;
463+
464+
template<auto __cw, typename _Fn>
465+
constexpr bool __is_constant_wrapper_v<constant_wrapper<__cw, _Fn>> = true;
466+
461467
template<_CwFixedValue _Tp>
462468
constexpr auto cw = constant_wrapper<_Tp>{};
463469
#endif
@@ -637,23 +643,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
637643
inline constexpr sorted_equivalent_t sorted_equivalent{};
638644
#endif
639645

640-
#if __glibcxx_function_ref // >= C++26
641-
template<auto>
642-
struct nontype_t
643-
{
644-
explicit nontype_t() = default;
645-
};
646-
647-
template<auto __val>
648-
constexpr nontype_t<__val> nontype{};
649-
650-
template<typename>
651-
inline constexpr bool __is_nontype_v = false;
652-
653-
template<auto __val>
654-
inline constexpr bool __is_nontype_v<nontype_t<__val>> = true;
655-
#endif
656-
657646
_GLIBCXX_END_NAMESPACE_VERSION
658647
} // namespace
659648

libstdc++-v3/src/c++23/std.cc.in

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3651,10 +3651,6 @@ export namespace std
36513651
using std::make_integer_sequence;
36523652
using std::move;
36533653
using std::move_if_noexcept;
3654-
#if __cpp_lib_function_ref
3655-
using std::nontype_t;
3656-
using std::nontype;
3657-
#endif
36583654
using std::pair;
36593655
using std::swap;
36603656
using std::operator==;

libstdc++-v3/testsuite/20_util/function_ref/assign.cc

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,7 @@
88
# error "Feature-test macro for function_ref has wrong value in <functional>"
99
#endif
1010

11-
using std::nontype;
12-
using std::nontype_t;
11+
using std::constant_wrapper;
1312
using std::function_ref;
1413

1514
using std::is_nothrow_move_assignable_v;
@@ -55,13 +54,13 @@ static_assert( ! is_assignable_v<function_ref<int(S)>, decltype(&S::x)> );
5554
static_assert( ! is_assignable_v<function_ref<int(S)>, decltype(&S::f)> );
5655

5756
static_assert( is_nothrow_assignable_v<function_ref<int(S)>,
58-
nontype_t<funS>> );
57+
constant_wrapper<funS>> );
5958
static_assert( is_nothrow_assignable_v<function_ref<int(S)>,
60-
nontype_t<&funS>> );
59+
constant_wrapper<&funS>> );
6160
static_assert( is_nothrow_assignable_v<function_ref<int(S)>,
62-
nontype_t<&S::x>> );
61+
constant_wrapper<&S::x>> );
6362
static_assert( is_nothrow_assignable_v<function_ref<int(S)>,
64-
nontype_t<&S::f>> );
63+
constant_wrapper<&S::f>> );
6564
struct Q
6665
{
6766
void operator()() const;
@@ -75,22 +74,22 @@ static_assert( ! is_assignable_v<function_ref<void() const>, Q&> );
7574
static_assert( ! is_assignable_v<function_ref<void() const>, const Q&> );
7675

7776
static_assert( is_nothrow_assignable_v<function_ref<void()>,
78-
nontype_t<Q{}>> );
77+
constant_wrapper<Q{}>> );
7978
static_assert( is_nothrow_assignable_v<function_ref<void() const>,
80-
nontype_t<Q{}>> );
79+
constant_wrapper<Q{}>> );
8180

8281
constexpr bool
8382
test_constexpr()
8483
{
85-
function_ref<void(S)> fp(nontype<funS>);
86-
fp = nontype<funS>;
87-
fp = nontype<&funS>;
88-
fp = nontype<&S::x>;
89-
fp = nontype<&S::f>;
84+
function_ref<void(S)> fp(std::cw<funS>);
85+
fp = std::cw<funS>;
86+
fp = std::cw<&funS>;
87+
fp = std::cw<&S::x>;
88+
fp = std::cw<&S::f>;
9089

9190
constexpr Q cq;
9291
function_ref<void() const> fq(cq);
93-
fq = nontype<cq>;
92+
fq = std::cw<cq>;
9493
return true;
9594
}
9695
static_assert( test_constexpr() );

libstdc++-v3/testsuite/20_util/function_ref/call.cc

Lines changed: 25 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
#include <utility>
55
#include <testsuite_hooks.h>
66

7-
using std::nontype;
87
using std::function_ref;
98

109
using std::is_same_v;
@@ -43,7 +42,7 @@ test01()
4342
VERIFY( f0() == 0 );
4443
VERIFY( std::move(f0)() == 0 );
4544

46-
function_ref<int()> f1{nontype<F{}>};
45+
function_ref<int()> f1{std::cw<F{}>};
4746
VERIFY( f1() == 1 );
4847
VERIFY( std::move(f1)() == 1 );
4948

@@ -53,7 +52,7 @@ test01()
5352
VERIFY( std::move(f2)() == 1 );
5453
VERIFY( std::move(std::as_const(f2))() == 1 );
5554

56-
function_ref<int() const> f3{nontype<F{}>};
55+
function_ref<int() const> f3{std::cw<F{}>};
5756
VERIFY( f3() == 1 );
5857
VERIFY( std::as_const(f3)() == 1 );
5958
VERIFY( std::move(f3)() == 1 );
@@ -71,11 +70,11 @@ test02()
7170
};
7271
F::Arg arg;
7372

74-
function_ref<int()> f0{std::nontype<F{}>, arg};
73+
function_ref<int()> f0{std::cw<F{}>, arg};
7574
VERIFY( f0() == 0 );
7675
VERIFY( std::move(f0)() == 0 );
7776

78-
function_ref<int() const> f1{std::nontype<F{}>, arg};
77+
function_ref<int() const> f1{std::cw<F{}>, arg};
7978
VERIFY( f1() == 1 );
8079
VERIFY( std::as_const(f1)() == 1 );
8180
}
@@ -91,11 +90,11 @@ test03()
9190
};
9291
F::Arg arg;
9392

94-
function_ref<int()> f0{std::nontype<F{}>, &arg};
93+
function_ref<int()> f0{std::cw<F{}>, &arg};
9594
VERIFY( f0() == 0 );
9695
VERIFY( std::move(f0)() == 0 );
9796

98-
function_ref<int() const> f1{std::nontype<F{}>, &arg};
97+
function_ref<int() const> f1{std::cw<F{}>, &arg};
9998
VERIFY( f1() == 1 );
10099
VERIFY( std::as_const(f1)() == 1 );
101100
}
@@ -108,15 +107,15 @@ test04()
108107
VERIFY( f0() == 0 );
109108
VERIFY( std::move(f0)() == 0 );
110109

111-
function_ref<int()> f1{nontype<fp>};
110+
function_ref<int()> f1{std::cw<fp>};
112111
VERIFY( f1() == 0 );
113112
VERIFY( std::move(f1)() == 0 );
114113

115114
const function_ref<int() const> f2{fp};
116115
VERIFY( f2() == 0 );
117116
VERIFY( std::move(f2)() == 0 );
118117

119-
const function_ref<int() const> f3{nontype<fp>};
118+
const function_ref<int() const> f3{std::cw<fp>};
120119
VERIFY( f2() == 0 );
121120
VERIFY( std::move(f2)() == 0 );
122121
}
@@ -130,14 +129,14 @@ int callback_ref(ftype& f, int x) { return f(x); }
130129
void
131130
test05()
132131
{
133-
function_ref<int(int)> r1(nontype<&callback_ptr>, &twice);
132+
function_ref<int(int)> r1(std::cw<&callback_ptr>, &twice);
134133
VERIFY( r1(2) == 4 );
135-
function_ref<int(int)> r2(nontype<&callback_ptr>, cube);
134+
function_ref<int(int)> r2(std::cw<&callback_ptr>, cube);
136135
VERIFY( r2(2) == 8 );
137136

138-
function_ref<int(int)> r3(nontype<&callback_ref>, twice);
137+
function_ref<int(int)> r3(std::cw<&callback_ref>, twice);
139138
VERIFY( r3(3) == 6 );
140-
function_ref<int(int)> r4(nontype<&callback_ref>, cube);
139+
function_ref<int(int)> r4(std::cw<&callback_ref>, cube);
141140
VERIFY( r4(3) == 27 );
142141
}
143142

@@ -174,37 +173,37 @@ test06()
174173
std::function_ref<const int&(int, int) const> e8(std::as_const(csr));
175174
VERIFY( &e8(0, 0) == &s.v );
176175

177-
std::function_ref<int&()> f1(std::nontype<&S::v>, sr);
176+
std::function_ref<int&()> f1(std::cw<&S::v>, sr);
178177
VERIFY( &f1() == &s.v );
179-
std::function_ref<const int&()> f2(std::nontype<&S::v>, sr);
178+
std::function_ref<const int&()> f2(std::cw<&S::v>, sr);
180179
VERIFY( &f2() == &s.v );
181-
std::function_ref<int&()> f3(std::nontype<&S::m>, sr);
180+
std::function_ref<int&()> f3(std::cw<&S::m>, sr);
182181
VERIFY( &f3() == &s.v );
183-
std::function_ref<const int&()> f4(std::nontype<&S::c>, sr);
182+
std::function_ref<const int&()> f4(std::cw<&S::c>, sr);
184183
VERIFY( &f4() == &s.v );
185184

186-
std::function_ref<const int&()> f5(std::nontype<&S::v>, csr);
185+
std::function_ref<const int&()> f5(std::cw<&S::v>, csr);
187186
VERIFY( &f5() == &s.v );
188-
std::function_ref<const int&()> f6(std::nontype<&S::c>, sr);
187+
std::function_ref<const int&()> f6(std::cw<&S::c>, sr);
189188
VERIFY( &f6() == &s.v );
190189
static_assert( !std::is_constructible_v<
191190
std::function_ref<int&()>,
192-
std::nontype_t<&S::c>, std::reference_wrapper<S>&>
191+
std::constant_wrapper<&S::c>, std::reference_wrapper<S>&>
193192
);
194193

195-
std::function_ref<int&()> f7(std::nontype<&S::v>, std::as_const(sr));
194+
std::function_ref<int&()> f7(std::cw<&S::v>, std::as_const(sr));
196195
VERIFY( &f7() == &s.v );
197-
std::function_ref<const int&()> f8(std::nontype<&S::m>, std::as_const(sr));
196+
std::function_ref<const int&()> f8(std::cw<&S::m>, std::as_const(sr));
198197
VERIFY( &f8() == &s.v );
199198

200199
// No rvalue reference_wrapper support
201200
static_assert( !std::is_constructible_v<
202201
std::function_ref<int&()>,
203-
std::nontype_t<&S::v>, std::reference_wrapper<S>>
202+
std::constant_wrapper<&S::v>, std::reference_wrapper<S>>
204203
);
205204
static_assert( !std::is_constructible_v<
206205
std::function_ref<int&()>,
207-
std::nontype_t<&S::v>, std::reference_wrapper<const S>>
206+
std::constant_wrapper<&S::v>, std::reference_wrapper<const S>>
208207
);
209208

210209
// reference to reference_wrapper are bound, so mutation are visible
@@ -232,9 +231,9 @@ test06()
232231
{ return &x; };
233232

234233
// identity of reference_wrapper is preserved
235-
std::function_ref<const std::reference_wrapper<S>*()> g1(std::nontype<id>, sr);
234+
std::function_ref<const std::reference_wrapper<S>*()> g1(std::cw<id>, sr);
236235
VERIFY( g1() == &sr );
237-
std::function_ref<const std::reference_wrapper<const S>*()> g2(std::nontype<id>, csr);
236+
std::function_ref<const std::reference_wrapper<const S>*()> g2(std::cw<id>, csr);
238237
VERIFY( g2() == &csr );
239238
}
240239

0 commit comments

Comments
 (0)