Skip to content

Commit 16eff85

Browse files
committed
__completion_signatures_of_t requires that get_completion_signatures<S,E...>() is a constant expression
1 parent abcd38a commit 16eff85

File tree

4 files changed

+37
-47
lines changed

4 files changed

+37
-47
lines changed

include/exec/sequence_senders.hpp

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -557,8 +557,7 @@ namespace experimental::execution
557557
#endif
558558

559559
template <class _Data, class... _What>
560-
struct __sequence_type_check_failure //
561-
: STDEXEC::__compile_time_error<__sequence_type_check_failure<_Data, _What...>>
560+
struct __sequence_type_check_failure : STDEXEC::__compile_time_error
562561
{
563562
static_assert(std::is_nothrow_move_constructible_v<_Data>,
564563
"The data member of sender_type_check_failure must be nothrow move "
@@ -570,16 +569,14 @@ namespace experimental::execution
570569
: __data_(static_cast<_Data&&>(data))
571570
{}
572571

573-
private:
574-
friend struct STDEXEC::__compile_time_error<__sequence_type_check_failure>;
575-
576572
[[nodiscard]]
577-
constexpr auto what() const noexcept -> char const *
573+
constexpr auto what() const noexcept -> char const * // NOLINT(modernize-use-override)
578574
{
579575
return "This sequence sender is not well-formed. It does not meet the requirements of a "
580576
"sequence sender type.";
581577
}
582578

579+
// public so that __sequence_type_check_failure is a structural type
583580
_Data __data_{};
584581
};
585582

@@ -845,10 +842,9 @@ namespace experimental::execution
845842
return STDEXEC::connect(static_cast<next_sender_of_t<_Receiver, __tfx_seq_t>&&>(__next),
846843
__stopped_means_break<_Receiver>{
847844
static_cast<_Receiver&&>(__rcvr)});
848-
// NOLINTNEXTLINE(bugprone-branch-clone)
849845
}
850846
else if constexpr (__subscribable_with_static_member<__tfx_seq_t, _Receiver>)
851-
{
847+
{ // NOLINT(bugprone-branch-clone)
852848
return __tfx_seq.subscribe(static_cast<__tfx_seq_t&&>(__tfx_seq),
853849
static_cast<_Receiver&&>(__rcvr));
854850
}

include/stdexec/__detail/__concepts.hpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,19 @@ namespace STDEXEC
9797
template <class _Ay, template <class...> class _Ty>
9898
concept __is_not_instance_of = !__is_instance_of<_Ay, _Ty>;
9999

100+
namespace __detail
101+
{
102+
template <auto>
103+
using __is_nttp = void;
104+
template <class _Ty, template <_Ty> class>
105+
using __nttp_test = void;
106+
} // namespace __detail
107+
108+
template <class _Ty>
109+
concept __structural = requires { typename __detail::__nttp_test<_Ty, __detail::__is_nttp>; };
110+
111+
static_assert(__structural<int>);
112+
100113
namespace __std
101114
{
102115

include/stdexec/__detail/__diagnostics.hpp

Lines changed: 19 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -144,13 +144,14 @@ namespace STDEXEC
144144
_WITH_PRETTY_SENDER_<_Sender>,
145145
_WITH_ENVIRONMENT_(_Env)...>;
146146

147-
#if __cpp_lib_constexpr_exceptions \
148-
>= 2025'02L // constexpr exception types, https://wg21.link/p3378
147+
#if __cpp_lib_constexpr_exceptions >= 2025'02L
149148

149+
// constexpr stdlib exception types, https://wg21.link/p3378
150150
using __exception = ::std::exception;
151151

152-
#elif __cpp_constexpr >= 2024'11L // constexpr virtual functions
152+
#elif __cpp_constexpr >= 2019'07L
153153

154+
// constexpr virtual functions
154155
struct __exception
155156
{
156157
constexpr __exception() noexcept = default;
@@ -163,8 +164,9 @@ namespace STDEXEC
163164
}
164165
};
165166

166-
#else // no constexpr virtual functions:
167+
#else
167168

169+
// no constexpr virtual functions
168170
struct __exception
169171
{
170172
constexpr __exception() noexcept = default;
@@ -176,23 +178,13 @@ namespace STDEXEC
176178
}
177179
};
178180

179-
#endif // __cpp_lib_constexpr_exceptions >= 2025'02L
181+
#endif
180182

181-
template <class _Derived>
182183
struct __compile_time_error : __exception
183-
{
184-
constexpr __compile_time_error() = default; // NOLINT (bugprone-crtp-constructor-accessibility)
185-
186-
[[nodiscard]]
187-
constexpr auto what() const noexcept -> char const *
188-
{
189-
return static_cast<_Derived const *>(this)->what();
190-
}
191-
};
184+
{ };
192185

193186
template <class _Data, class... _What>
194-
struct __sender_type_check_failure //
195-
: __compile_time_error<__sender_type_check_failure<_Data, _What...>>
187+
struct __sender_type_check_failure : __compile_time_error
196188
{
197189
static_assert(std::is_nothrow_move_constructible_v<_Data>,
198190
"The data member of sender_type_check_failure must be nothrow move "
@@ -204,34 +196,24 @@ namespace STDEXEC
204196
: __data_(static_cast<_Data &&>(data))
205197
{}
206198

207-
private:
208-
friend struct __compile_time_error<__sender_type_check_failure>;
209-
210199
[[nodiscard]]
211-
constexpr auto what() const noexcept -> char const *
200+
constexpr auto what() const noexcept -> char const * // NOLINT(modernize-use-override)
212201
{
213202
return "This sender is not well-formed. It does not meet the requirements of a sender type.";
214203
}
215204

205+
// public so that __sender_type_check_failure is a structural type
216206
_Data __data_{};
217207
};
218208

219-
struct dependent_sender_error : __compile_time_error<dependent_sender_error>
209+
struct dependent_sender_error : __compile_time_error
220210
{
221-
constexpr explicit dependent_sender_error(char const *what) noexcept
222-
: what_(what)
223-
{}
224-
225-
private:
226-
friend struct __compile_time_error<dependent_sender_error>;
227-
228211
[[nodiscard]]
229-
constexpr auto what() const noexcept -> char const *
212+
constexpr auto what() const noexcept -> char const * // NOLINT(modernize-use-override)
230213
{
231-
return what_;
214+
return "This sender needs to know its execution environment before it can "
215+
"know how it will complete.";
232216
}
233-
234-
char const *what_;
235217
};
236218

237219
// A specialization of _ERROR_ to be used to report dependent sender. It inherits
@@ -257,11 +239,8 @@ namespace STDEXEC
257239
using __errors = _ERROR_;
258240
using __all = _ERROR_;
259241

260-
constexpr _ERROR_() noexcept
261-
: dependent_sender_error{"This sender needs to know its execution environment before it can "
262-
"know how it will "
263-
"complete."}
264-
{}
242+
constexpr _ERROR_() = default;
243+
constexpr ~_ERROR_() = default;
265244

266245
STDEXEC_ATTRIBUTE(host, device) constexpr auto operator+() const -> _ERROR_;
267246

@@ -274,6 +253,8 @@ namespace STDEXEC
274253
constexpr auto operator,(const _ERROR_<Other...> &) const -> _ERROR_<Other...>;
275254
};
276255

256+
static_assert(__structural<_ERROR_<dependent_sender_error>>);
257+
277258
// By making __dependent_sender_error_t an alias for _ERROR_<...>, we ensure that
278259
// it will get propagated correctly through various metafunctions.
279260
template <class _Sender>

include/stdexec/__detail/__get_completion_signatures.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,7 @@ namespace STDEXEC
305305
template <class _Sender, class... _Env>
306306
requires enable_sender<__decay_t<_Sender>>
307307
using __completion_signatures_of_t =
308-
decltype(STDEXEC::get_completion_signatures<_Sender, _Env...>());
308+
__mtypeof<STDEXEC::get_completion_signatures<_Sender, _Env...>()>;
309309

310310
///////////////////////////////////////////////////////////////////////////////////////////////////
311311
// __get_child_completion_signatures

0 commit comments

Comments
 (0)