From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from smtp001-out.apm-internet.net (smtp001-out.apm-internet.net [85.119.248.222]) by sourceware.org (Postfix) with ESMTPS id ED82A3858D1E for ; Mon, 18 Apr 2022 19:55:48 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org ED82A3858D1E Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=sandoe.co.uk Authentication-Results: sourceware.org; spf=none smtp.mailfrom=sandoe.co.uk Received: (qmail 90394 invoked from network); 18 Apr 2022 19:55:47 -0000 X-APM-Out-ID: 16503117479038 X-APM-Authkey: 257869/1(257869/1) 3 Received: from unknown (HELO ?192.168.1.214?) (81.138.1.83) by smtp001.apm-internet.net with SMTP; 18 Apr 2022 19:55:47 -0000 Content-Type: text/plain; charset=utf-8 Mime-Version: 1.0 (Mac OS X Mail 12.4 \(3445.104.21\)) Subject: Re: [PATCH] c++, coroutines: Avoid expanding within templates [PR103868] From: Iain Sandoe In-Reply-To: Date: Mon, 18 Apr 2022 20:55:46 +0100 Cc: gcc-patches , Martin Liska Content-Transfer-Encoding: quoted-printable Message-Id: References: <20220418135936.24757-1-iain@sandoe.co.uk> To: Eric Gallager X-Mailer: Apple Mail (2.3445.104.21) X-Spam-Status: No, score=-14.7 required=5.0 tests=BAYES_00, GIT_PATCH_0, KAM_COUK, KAM_DMARC_STATUS, KAM_LAZY_DOMAIN_SECURITY, RCVD_IN_DNSWL_LOW, SPF_HELO_NONE, SPF_NONE, TXREP, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 18 Apr 2022 19:55:56 -0000 cc-ing Martin on this question ..=20 > On 18 Apr 2022, at 20:49, Eric Gallager wrote: >=20 > On Mon, Apr 18, 2022 at 10:01 AM Iain Sandoe via Gcc-patches > wrote: >>=20 >> From: Nathan Sidwell >>=20 >> This is a forward-port of a patch by Nathan (against 10.x) which = fixes an open >> PR. >>=20 >> We are ICEing because we ended up tsubst_copying something that had = already >> been tsubst, leading to an assert failure (mostly such repeated = tsubsting is >> harmless). >>=20 >> We had a non-dependent co_await in a non-dependent-type template fn, = so we >> processed it at definition time, and then reprocessed at = instantiation time. >> We fix this here by deferring substitution while processing = templates. >>=20 >> Additional observations (for a better future fix, in the GCC13 = timescale): >>=20 >> Exprs only have dependent type if at least one operand is dependent = which was >> what the current code was intending to do. Coroutines have the = additional >> wrinkle, that the current fn's type is an implicit operand. >>=20 >> So, if the coroutine function's type is not dependent, and the = operand is not >> dependent, we should determine the type of the co_await expression = using the >> DEPENDENT_EXPR wrapper machinery. That allows us to determine the >> subexpression type, but leave its operand unchanged and then = instantiate it >> later. >>=20 >> Tested on x86_64-darwin (it does also fix the original testcase, but = that is >> far too time-consuming for the testsuite). >>=20 >> OK for master? / backports? (when?) >> thanks, >> Iain >>=20 >> PR c++/103868 >>=20 >> gcc/cp/ChangeLog: >>=20 >> * coroutines.cc (finish_co_await_expr): Do not process = non-dependent >> coroutine expressions at template definition time. >> (finish_co_yield_expr): Likewise. >> (finish_co_return_stmt): Likewise. >>=20 >> gcc/testsuite/ChangeLog: >>=20 >> * g++.dg/coroutines/pr103868.C: New test. >>=20 >> Co-Authored-by: Iain Sandoe >> --- >> gcc/cp/coroutines.cc | 18 +- >> gcc/testsuite/g++.dg/coroutines/pr103868.C | 7390 = ++++++++++++++++++++ >> 2 files changed, 7396 insertions(+), 12 deletions(-) >> create mode 100644 gcc/testsuite/g++.dg/coroutines/pr103868.C >>=20 >> diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc >> index cdf6503c4d3..a9ce6e050dd 100644 >> --- a/gcc/cp/coroutines.cc >> +++ b/gcc/cp/coroutines.cc >> @@ -1148,10 +1148,8 @@ finish_co_await_expr (location_t kw, tree = expr) >> extraneous warnings during substitution. */ >> suppress_warning (current_function_decl, OPT_Wreturn_type); >>=20 >> - /* If we don't know the promise type, we can't proceed, build the >> - co_await with the expression unchanged. */ >> - tree functype =3D TREE_TYPE (current_function_decl); >> - if (dependent_type_p (functype) || type_dependent_expression_p = (expr)) >> + /* Defer processing when we have dependent types. */ >> + if (processing_template_decl) >> { >> tree aw_expr =3D build5_loc (kw, CO_AWAIT_EXPR, = unknown_type_node, expr, >> NULL_TREE, NULL_TREE, NULL_TREE, >> @@ -1222,10 +1220,8 @@ finish_co_yield_expr (location_t kw, tree = expr) >> extraneous warnings during substitution. */ >> suppress_warning (current_function_decl, OPT_Wreturn_type); >>=20 >> - /* If we don't know the promise type, we can't proceed, build the >> - co_await with the expression unchanged. */ >> - tree functype =3D TREE_TYPE (current_function_decl); >> - if (dependent_type_p (functype) || type_dependent_expression_p = (expr)) >> + /* Defer processing when we have dependent types. */ >> + if (processing_template_decl) >> return build2_loc (kw, CO_YIELD_EXPR, unknown_type_node, expr, = NULL_TREE); >>=20 >> if (!coro_promise_type_found_p (current_function_decl, kw)) >> @@ -1307,10 +1303,8 @@ finish_co_return_stmt (location_t kw, tree = expr) >> && check_for_bare_parameter_packs (expr)) >> return error_mark_node; >>=20 >> - /* If we don't know the promise type, we can't proceed, build the >> - co_return with the expression unchanged. */ >> - tree functype =3D TREE_TYPE (current_function_decl); >> - if (dependent_type_p (functype) || type_dependent_expression_p = (expr)) >> + /* Defer processing when we have dependent types. */ >> + if (processing_template_decl) >> { >> /* co_return expressions are always void type, regardless of = the >> expression type. */ >> diff --git a/gcc/testsuite/g++.dg/coroutines/pr103868.C = b/gcc/testsuite/g++.dg/coroutines/pr103868.C >> new file mode 100644 >> index 00000000000..f7b7e3bad54 >> --- /dev/null >> +++ b/gcc/testsuite/g++.dg/coroutines/pr103868.C >> @@ -0,0 +1,7390 @@ >> +// { dg-do compile } >> +// { dg-additional-options "-fpreprocessed -std=3Dgnu++20 -w = -fconcepts" } >> +// The ICE is fixed, but the reduced testcase has excess errors: >=20 > Hi, this comment says the testcase is "reduced" and yet it is still > very large; is this really as far as it can be reduced? Just wondering > for informational purposes=E2=80=A6 I think one would have to start with the original code, and then make an = =E2=80=9Cintestingness test=E2=80=9D that fails for the broken compiler = and passes with the fixed (which would also resolve the problem with the = reduced case producing unrelated error output). IIRC the original code takes a few minutes to compile on my laptop, so = i=E2=80=99d expect it might be very time-consuming to do - perhaps = Martin has some ideas? Iain >=20 >> +// { dg-excess-errors {concept '__indirectly_readable_impl' has = multiple template parameter lists} } >> +namespace std { >> +typedef decltype(nullptr) nullptr_t; >> +template struct char_traits; >> +} // namespace std >> +namespace doctest { >> +class String { >> +public: >> + String(const char *in); >> +}; >> +namespace assertType { >> +enum Enum { >> + is_warn =3D 1, >> + is_check =3D 2 * is_warn, >> + is_require =3D 2 * is_check, >> + is_normal =3D 2 * is_require, >> + is_throws =3D 2 * is_normal, >> + is_throws_as =3D 2 * is_throws, >> + is_throws_with =3D 2 * is_throws_as, >> + is_nothrow =3D 2 * is_throws_with, >> + is_false =3D 2 * is_nothrow, >> + is_unary =3D 2 * is_false, >> + is_eq =3D 2 * is_unary, >> + is_ne =3D 2 * is_eq, >> + is_lt =3D 2 * is_ne, >> + is_gt =3D 2 * is_lt, >> + is_ge =3D 2 * is_gt, >> + is_le =3D 2 * is_ge, >> + DT_WARN =3D is_normal | is_warn, >> + DT_CHECK =3D is_normal | is_check, >> + DT_REQUIRE =3D is_normal | is_require, >> + DT_WARN_FALSE =3D is_normal | is_false | is_warn, >> + DT_CHECK_FALSE =3D is_normal | is_false | is_check, >> + DT_REQUIRE_FALSE =3D is_normal | is_false | is_require, >> + DT_WARN_THROWS =3D is_throws | is_warn, >> + DT_CHECK_THROWS =3D is_throws | is_check, >> + DT_REQUIRE_THROWS =3D is_throws | is_require, >> + DT_WARN_THROWS_AS =3D is_throws_as | is_warn, >> + DT_CHECK_THROWS_AS =3D is_throws_as | is_check, >> + DT_REQUIRE_THROWS_AS =3D is_throws_as | is_require, >> + DT_WARN_THROWS_WITH =3D is_throws_with | is_warn, >> + DT_CHECK_THROWS_WITH =3D is_throws_with | is_check, >> + DT_REQUIRE_THROWS_WITH =3D is_throws_with | is_require, >> + DT_WARN_THROWS_WITH_AS =3D is_throws_with | is_throws_as | = is_warn, >> + DT_CHECK_THROWS_WITH_AS =3D is_throws_with | is_throws_as | = is_check, >> + DT_REQUIRE_THROWS_WITH_AS =3D is_throws_with | is_throws_as | = is_require, >> + DT_WARN_NOTHROW =3D is_nothrow | is_warn, >> + DT_CHECK_NOTHROW =3D is_nothrow | is_check, >> + DT_REQUIRE_NOTHROW =3D is_nothrow | is_require, >> + DT_WARN_EQ =3D is_normal | is_eq | is_warn, >> + DT_CHECK_EQ =3D is_normal | is_eq | is_check, >> + DT_REQUIRE_EQ =3D is_normal | is_eq | is_require, >> + DT_WARN_NE =3D is_normal | is_ne | is_warn, >> + DT_CHECK_NE =3D is_normal | is_ne | is_check, >> + DT_REQUIRE_NE =3D is_normal | is_ne | is_require, >> + DT_WARN_GT =3D is_normal | is_gt | is_warn, >> + DT_CHECK_GT =3D is_normal | is_gt | is_check, >> + DT_REQUIRE_GT =3D is_normal | is_gt | is_require, >> + DT_WARN_LT =3D is_normal | is_lt | is_warn, >> + DT_CHECK_LT =3D is_normal | is_lt | is_check, >> + DT_REQUIRE_LT =3D is_normal | is_lt | is_require, >> + DT_WARN_GE =3D is_normal | is_ge | is_warn, >> + DT_CHECK_GE =3D is_normal | is_ge | is_check, >> + DT_REQUIRE_GE =3D is_normal | is_ge | is_require, >> + DT_WARN_LE =3D is_normal | is_le | is_warn, >> + DT_CHECK_LE =3D is_normal | is_le | is_check, >> + DT_REQUIRE_LE =3D is_normal | is_le | is_require, >> + DT_WARN_UNARY =3D is_normal | is_unary | is_warn, >> + DT_CHECK_UNARY =3D is_normal | is_unary | is_check, >> + DT_REQUIRE_UNARY =3D is_normal | is_unary | is_require, >> + DT_WARN_UNARY_FALSE =3D is_normal | is_false | is_unary | is_warn, >> + DT_CHECK_UNARY_FALSE =3D is_normal | is_false | is_unary | = is_check, >> + DT_REQUIRE_UNARY_FALSE =3D is_normal | is_false | is_unary | = is_require, >> +}; >> +} >> +struct AssertData {}; >> +namespace detail { >> +template auto declval() noexcept -> = decltype(declval(0)); >> +namespace has_insertion_operator_impl {} >> +struct Subcase { >> + Subcase(const String &name, const char *file, int line); >> + operator bool() const; >> +}; >> +struct Result { >> + bool m_passed; >> +}; >> +template struct Expression_lhs {}; >> +struct ExpressionDecomposer {}; >> +struct ResultBuilder : public AssertData { >> + ResultBuilder(assertType::Enum at, const char *file, int line, >> + const char *expr, const char *exception_type =3D "", >> + const char *exception_string =3D ""); >> + bool log(); >> + void react() const; >> +}; >> +} // namespace detail >> +} // namespace doctest >> +namespace std { >> +typedef long unsigned int size_t; >> +typedef long int ptrdiff_t; >> +inline namespace __cxx11 __attribute__((__abi_tag__("cxx11"))) {} >> +template class allocator; >> +namespace __cxx11 { >> +template , >> + typename _Alloc =3D allocator<_CharT>> >> +class basic_string; >> +} >> +typedef basic_string string; >> +} // namespace std >> +typedef long unsigned int size_t; >> +typedef struct __mbstate_t; >> +namespace std { >> +template > >> +class basic_streambuf; >> +template > >> +class basic_iostream; >> +} // namespace std >> +extern "C++" { >> +namespace std { >> +class exception { >> +public: >> +}; >> +} // namespace std >> +} >> +extern "C++" { >> +namespace std { >> +class bad_cast : public exception { >> +public: >> +}; >> +} // namespace std >> +[[__nodiscard__]] inline void *operator new(std::size_t, void *__p) = noexcept {} >> +namespace std { >> +namespace __exception_ptr { >> +class exception_ptr; >> +} >> +using __exception_ptr::exception_ptr; >> +namespace __exception_ptr { >> +class exception_ptr { >> +public: >> + exception_ptr(nullptr_t); >> +}; >> +} // namespace __exception_ptr >> +} // namespace std >> +} >> +namespace std __attribute__((__visibility__("default"))) { >> + template struct integral_constant { >> + static constexpr _Tp value =3D __v; >> + typedef _Tp value_type; >> + typedef integral_constant<_Tp, __v> type; >> + constexpr operator value_type() const noexcept { return value; } >> + }; >> + typedef integral_constant true_type; >> + typedef integral_constant false_type; >> + template using __bool_constant =3D = integral_constant; >> + template using bool_constant =3D = integral_constant; >> + template struct conditional; >> + template struct __type_identity { using type =3D = _Type; }; >> + template struct __or_; >> + template >> + struct __or_<_B1, _B2> : public conditional<_B1::value, _B1, = _B2>::type {}; >> + template >> + struct __or_<_B1, _B2, _B3, _Bn...> >> + : public conditional<_B1::value, _B1, __or_<_B2, _B3, = _Bn...>>::type {}; >> + template struct __and_; >> + template >> + struct __and_<_B1, _B2> : public conditional<_B1::value, _B2, = _B1>::type {}; >> + template >> + struct __and_<_B1, _B2, _B3, _Bn...> >> + : public conditional<_B1::value, __and_<_B2, _B3, _Bn...>, = _B1>::type {}; >> + template >> + struct __not_ : public __bool_constant {}; >> + template >> + inline constexpr bool __and_v =3D __and_<_Bn...>::value; >> + template struct conjunction : __and_<_Bn...> {}; >> + template struct is_reference; >> + template struct is_function; >> + template struct is_void; >> + template struct __is_array_unknown_bounds; >> + template >> + constexpr true_type = __is_complete_or_unbounded(__type_identity<_Tp>) { >> + return {}; >> + } >> + template > + typename _NestedType =3D typename _TypeIdentity::type> >> + constexpr typename __or_, = is_function<_NestedType>, >> + is_void<_NestedType>, >> + = __is_array_unknown_bounds<_NestedType>>::type >> + __is_complete_or_unbounded(_TypeIdentity) { >> + return {}; >> + } >> + template struct __success_type { typedef _Tp type; = }; >> + template struct remove_cv; >> + template using __remove_cv_t =3D typename = remove_cv<_Tp>::type; >> + template struct is_const; >> + template struct __is_void_helper : public false_type = {}; >> + template <> struct __is_void_helper : public true_type {}; >> + template >> + struct is_void : public __is_void_helper<__remove_cv_t<_Tp>>::type = {}; >> + template struct __is_integral_helper : public = false_type {}; >> + template <> struct __is_integral_helper : public true_type = {}; >> + template <> struct __is_integral_helper : public true_type = {}; >> + template >> + struct is_integral : public = __is_integral_helper<__remove_cv_t<_Tp>>::type {}; >> + template struct __is_floating_point_helper : public = false_type {}; >> + template >> + struct is_floating_point >> + : public __is_floating_point_helper<__remove_cv_t<_Tp>>::type = {}; >> + template struct is_array : public false_type {}; >> + template >> + struct is_array<_Tp[_Size]> : public true_type {}; >> + template struct __is_pointer_helper : public false_type = {}; >> + template >> + struct __is_pointer_helper<_Tp *> : public true_type {}; >> + template >> + struct is_pointer : public = __is_pointer_helper<__remove_cv_t<_Tp>>::type {}; >> + template struct is_lvalue_reference : public false_type = {}; >> + template struct is_rvalue_reference : public false_type = {}; >> + template >> + struct __is_member_object_pointer_helper : public false_type {}; >> + template >> + struct is_member_object_pointer >> + : public = __is_member_object_pointer_helper<__remove_cv_t<_Tp>>::type {}; >> + template >> + struct __is_member_function_pointer_helper : public false_type {}; >> + template >> + struct __is_member_function_pointer_helper<_Tp _Cp::*> >> + : public is_function<_Tp>::type {}; >> + template >> + struct is_member_function_pointer >> + : public = __is_member_function_pointer_helper<__remove_cv_t<_Tp>>::type {}; >> + template >> + struct is_enum : public integral_constant = {}; >> + template >> + struct is_union : public integral_constant = {}; >> + template >> + struct is_class : public integral_constant = {}; >> + template >> + struct is_function : public __bool_constant::value> {}; >> + template struct is_function<_Tp &> : public = false_type {}; >> + template struct __is_null_pointer_helper : public = false_type {}; >> + template >> + struct is_null_pointer >> + : public __is_null_pointer_helper<__remove_cv_t<_Tp>>::type { >> + } __attribute__((__deprecated__("use '" >> + "std::is_null_pointer" >> + "' instead"))); >> + template >> + struct is_reference >> + : public __or_, = is_rvalue_reference<_Tp>>::type { >> + }; >> + template >> + struct is_arithmetic >> + : public __or_, is_floating_point<_Tp>>::type = {}; >> + template >> + struct is_fundamental : public __or_, = is_void<_Tp>, >> + is_null_pointer<_Tp>>::type = {}; >> + template >> + struct is_object >> + : public __not_< >> + __or_, is_reference<_Tp>, = is_void<_Tp>>>::type {}; >> + template struct is_member_pointer; >> + template >> + struct is_scalar >> + : public __or_, is_enum<_Tp>, = is_pointer<_Tp>, >> + is_member_pointer<_Tp>, = is_null_pointer<_Tp>>::type {}; >> + template >> + struct __is_member_pointer_helper : public false_type {}; >> + template >> + struct is_member_pointer >> + : public __is_member_pointer_helper<__remove_cv_t<_Tp>>::type = {}; >> + template using __void_t =3D void; >> + template >> + struct __is_referenceable : public false_type {}; >> + template >> + struct __is_referenceable<_Tp, __void_t<_Tp &>> : public true_type = {}; >> + template struct is_const : public false_type {}; >> + template struct is_const<_Tp const> : public = true_type {}; >> + template struct is_volatile : public false_type {}; >> + template >> + struct is_trivial : public integral_constant { >> + static_assert( >> + std::__is_complete_or_unbounded(__type_identity<_Tp>{}), >> + "template argument must be a complete class or an unbounded = array"); >> + }; >> + template >> + struct is_trivially_copyable >> + : public integral_constant = { >> + static_assert( >> + std::__is_complete_or_unbounded(__type_identity<_Tp>{}), >> + "template argument must be a complete class or an unbounded = array"); >> + }; >> + template >> + struct is_standard_layout >> + : public integral_constant = {}; >> + template >> + struct is_empty : public integral_constant = {}; >> + template ::value> >> + struct __is_signed_helper : public false_type {}; >> + template >> + struct is_signed : public __is_signed_helper<_Tp>::type {}; >> + template _Up = __declval(int); >> + template auto declval() = noexcept->decltype(__declval<_Tp>(0)); >> + template struct extent; >> + template struct remove_all_extents; >> + template >> + struct __is_array_known_bounds >> + : public integral_constant::value > 0)> {}; >> + template >> + struct __is_array_unknown_bounds >> + : public __and_, __not_>> {}; >> + struct __do_is_destructible_impl { >> + template ().~_Tp())> >> + static true_type __test(int); >> + }; >> + template >> + struct __is_destructible_impl : public __do_is_destructible_impl { >> + typedef decltype(__test<_Tp>(0)) type; >> + }; >> + template > + bool =3D __or_, = __is_array_unknown_bounds<_Tp>, >> + is_function<_Tp>>::value, >> + bool =3D __or_, = is_scalar<_Tp>>::value> >> + struct __is_destructible_safe; >> + template >> + struct __is_destructible_safe<_Tp, false, false> >> + : public __is_destructible_impl< >> + typename remove_all_extents<_Tp>::type>::type {}; >> + template >> + struct is_destructible : public __is_destructible_safe<_Tp>::type = { >> + static_assert( >> + std::__is_complete_or_unbounded(__type_identity<_Tp>{}), >> + "template argument must be a complete class or an unbounded = array"); >> + }; >> + struct __do_is_nt_destructible_impl { >> + template >> + static __bool_constant().~_Tp())> = __test(int); >> + }; >> + template >> + struct __is_nt_destructible_impl : public = __do_is_nt_destructible_impl { >> + typedef decltype(__test<_Tp>(0)) type; >> + }; >> + template > + bool =3D __or_, = __is_array_unknown_bounds<_Tp>, >> + is_function<_Tp>>::value, >> + bool =3D __or_, = is_scalar<_Tp>>::value> >> + struct __is_nt_destructible_safe; >> + template >> + struct __is_nt_destructible_safe<_Tp, false, false> >> + : public __is_nt_destructible_impl< >> + typename remove_all_extents<_Tp>::type>::type {}; >> + template >> + struct is_nothrow_destructible : public = __is_nt_destructible_safe<_Tp>::type { >> + }; >> + template >> + struct __is_constructible_impl >> + : public __bool_constant<__is_constructible(_Tp, _Args...)> = {}; >> + template >> + struct is_constructible : public __is_constructible_impl<_Tp, = _Args...> {}; >> + template >> + struct is_default_constructible : public = __is_constructible_impl<_Tp>::type { >> + }; >> + template ::value> >> + struct __is_copy_constructible_impl; >> + template >> + struct __is_copy_constructible_impl<_Tp, true> >> + : public __is_constructible_impl<_Tp, const _Tp &> {}; >> + template >> + struct is_copy_constructible : public = __is_copy_constructible_impl<_Tp> {}; >> + template ::value> >> + struct __is_move_constructible_impl; >> + template >> + struct __is_move_constructible_impl<_Tp, true> >> + : public __is_constructible_impl<_Tp, _Tp &&> {}; >> + template >> + struct is_move_constructible : public = __is_move_constructible_impl<_Tp> {}; >> + template >> + using __is_nothrow_constructible_impl =3D >> + __bool_constant<__is_nothrow_constructible(_Tp, _Args...)>; >> + template >> + struct is_nothrow_constructible >> + : public __is_nothrow_constructible_impl<_Tp, _Args...>::type = {}; >> + template >> + struct is_nothrow_default_constructible >> + : public __bool_constant<__is_nothrow_constructible(_Tp)> {}; >> + template ::value> >> + struct __is_nothrow_copy_constructible_impl; >> + template >> + struct __is_nothrow_copy_constructible_impl<_Tp, true> >> + : public __is_nothrow_constructible_impl<_Tp, const _Tp &> {}; >> + template >> + struct is_nothrow_copy_constructible >> + : public __is_nothrow_copy_constructible_impl<_Tp>::type { >> + static_assert( >> + std::__is_complete_or_unbounded(__type_identity<_Tp>{}), >> + "template argument must be a complete class or an unbounded = array"); >> + }; >> + template ::value> >> + struct __is_nothrow_move_constructible_impl; >> + template >> + struct is_nothrow_move_constructible >> + : public __is_nothrow_move_constructible_impl<_Tp>::type {}; >> + template >> + struct is_assignable : public __bool_constant<__is_assignable(_Tp, = _Up)> {}; >> + template ::value> >> + struct __is_copy_assignable_impl; >> + template >> + struct __is_copy_assignable_impl<_Tp, true> >> + : public __bool_constant<__is_assignable(_Tp &, const _Tp &)> = {}; >> + template >> + struct is_copy_assignable : public = __is_copy_assignable_impl<_Tp>::type {}; >> + template ::value> >> + struct __is_move_assignable_impl; >> + template >> + struct __is_move_assignable_impl<_Tp, true> >> + : public __bool_constant<__is_assignable(_Tp &, _Tp &&)> {}; >> + template >> + struct is_move_assignable : public = __is_move_assignable_impl<_Tp>::type {}; >> + template ::value> >> + struct __is_trivially_copy_constructible_impl; >> + template >> + struct __is_trivially_copy_constructible_impl<_Tp, true> >> + : public __and_<__is_copy_constructible_impl<_Tp>, >> + integral_constant> + _Tp, const _Tp = &)>> {}; >> + template >> + struct is_trivially_copy_constructible >> + : public __is_trivially_copy_constructible_impl<_Tp> {}; >> + template ::value> >> + struct __is_trivially_move_constructible_impl; >> + template >> + struct __is_trivially_move_constructible_impl<_Tp, true> >> + : public __and_<__is_move_constructible_impl<_Tp>, >> + integral_constant> + _Tp, _Tp &&)>> {}; >> + template >> + struct is_trivially_move_constructible >> + : public __is_trivially_move_constructible_impl<_Tp> {}; >> + template ::value> >> + struct __is_trivially_copy_assignable_impl; >> + template >> + struct __is_trivially_copy_assignable_impl<_Tp, true> >> + : public __bool_constant<__is_trivially_assignable(_Tp &, = const _Tp &)> { >> + }; >> + template >> + struct is_trivially_copy_assignable >> + : public __is_trivially_copy_assignable_impl<_Tp> {}; >> + template ::value> >> + struct __is_trivially_move_assignable_impl; >> + template >> + struct __is_trivially_move_assignable_impl<_Tp, true> >> + : public __bool_constant<__is_trivially_assignable(_Tp &, _Tp = &&)> {}; >> + template >> + struct is_trivially_move_assignable >> + : public __is_trivially_move_assignable_impl<_Tp> {}; >> + template >> + struct is_trivially_destructible >> + : public __and_<__is_destructible_safe<_Tp>, >> + = __bool_constant<__has_trivial_destructor(_Tp)>> {}; >> + template >> + struct alignment_of : public integral_constant { >> + static_assert( >> + std::__is_complete_or_unbounded(__type_identity<_Tp>{}), >> + "template argument must be a complete class or an unbounded = array"); >> + }; >> + template >> + struct is_same : public integral_constant {}; >> + template >> + struct is_base_of >> + : public integral_constant {}; >> + template > + bool =3D >> + __or_, is_function<_To>, = is_array<_To>>::value> >> + struct __is_convertible_helper; >> + template >> + class __is_convertible_helper<_From, _To, false> { >> + template static void __test_aux(_To1) noexcept; >> + template > + typename =3D = decltype(__test_aux<_To1>(std::declval<_From1>()))> >> + static true_type __test(int); >> + >> + public: >> + typedef decltype(__test<_From, _To>(0)) type; >> + }; >> + template >> + struct is_convertible : public __is_convertible_helper<_From, = _To>::type {}; >> + template > + bool =3D >> + __or_, is_function<_To>, = is_array<_To>>::value> >> + struct __is_nt_convertible_helper : is_void<_To> {}; >> + template >> + struct is_nothrow_convertible >> + : public __is_nt_convertible_helper<_From, _To>::type {}; >> + template struct remove_const { typedef _Tp type; }; >> + template struct remove_cv { using type =3D _Tp; }; >> + template struct remove_cv { using type =3D= _Tp; }; >> + template struct add_const; >> + template >> + using remove_const_t =3D typename remove_const<_Tp>::type; >> + template using remove_cv_t =3D typename = remove_cv<_Tp>::type; >> + template struct remove_reference { typedef _Tp = type; }; >> + template struct remove_reference<_Tp &> { typedef = _Tp type; }; >> + template struct remove_reference<_Tp &&> { typedef = _Tp type; }; >> + template ::value> >> + struct __add_rvalue_reference_helper { >> + typedef _Tp type; >> + }; >> + template >> + struct add_rvalue_reference : public = __add_rvalue_reference_helper<_Tp> {}; >> + template >> + using remove_reference_t =3D typename remove_reference<_Tp>::type; >> + template >> + using add_rvalue_reference_t =3D typename = add_rvalue_reference<_Tp>::type; >> + template >> + struct __cv_selector; >> + template >> + struct __cv_selector<_Unqualified, false, false> { >> + typedef _Unqualified __type; >> + }; >> + template > + bool _IsConst =3D is_const<_Qualified>::value, >> + bool _IsVol =3D is_volatile<_Qualified>::value> >> + class __match_cv_qualifiers { >> + typedef __cv_selector<_Unqualified, _IsConst, _IsVol> __match; >> + >> + public: >> + typedef typename __match::__type __type; >> + }; >> + template struct __make_unsigned { typedef _Tp = __type; }; >> + template ::value, >> + bool _IsEnum =3D is_enum<_Tp>::value> >> + class __make_unsigned_selector; >> + template class __make_unsigned_selector<_Tp, true, = false> { >> + using __unsigned_type =3D >> + typename __make_unsigned<__remove_cv_t<_Tp>>::__type; >> + >> + public: >> + using __type =3D typename __match_cv_qualifiers<_Tp, = __unsigned_type>::__type; >> + }; >> + template struct make_unsigned { >> + typedef typename __make_unsigned_selector<_Tp>::__type type; >> + }; >> + template struct remove_all_extents { typedef _Tp = type; }; >> + template >> + using remove_all_extents_t =3D typename = remove_all_extents<_Tp>::type; >> + template ::value, >> + bool _IsFunction =3D is_function<_Up>::value> >> + struct __decay_selector; >> + template struct __decay_selector<_Up, false, false> = { >> + typedef __remove_cv_t<_Up> __type; >> + }; >> + template class decay { >> + typedef typename remove_reference<_Tp>::type __remove_type; >> + >> + public: >> + typedef typename __decay_selector<__remove_type>::__type type; >> + }; >> + template using __decay_t =3D typename = decay<_Tp>::type; >> + template struct enable_if {}; >> + template struct enable_if { typedef _Tp = type; }; >> + template >> + using __enable_if_t =3D typename enable_if<_Cond, _Tp>::type; >> + template >> + using _Require =3D __enable_if_t<__and_<_Cond...>::value>; >> + template >> + struct conditional { >> + typedef _Iftrue type; >> + }; >> + template >> + struct conditional { >> + typedef _Iffalse type; >> + }; >> + template >> + using __remove_cvref_t =3D >> + typename remove_cv::type>::type; >> + template struct result_of; >> + struct __invoke_memfun_deref; >> + struct __invoke_other {}; >> + template >> + struct __result_of_success : __success_type<_Tp> { >> + using __invoke_type =3D _Tag; >> + }; >> + struct __result_of_memfun_ref_impl {}; >> + template >> + struct __result_of_memfun_ref : private = __result_of_memfun_ref_impl {}; >> + struct __result_of_memfun_deref_impl { >> + template >> + static __result_of_success< >> + decltype(((*std::declval<_Tp1>()).* >> + std::declval<_Fp>())(std::declval<_Args>()...)), >> + __invoke_memfun_deref> >> + _S_test(int); >> + }; >> + template >> + struct __result_of_memfun_deref : private = __result_of_memfun_deref_impl { >> + typedef decltype(_S_test<_MemPtr, _Arg, _Args...>(0)) type; >> + }; >> + template >> + struct __result_of_memfun; >> + template >> + struct __result_of_memfun<_Res _Class::*, _Arg, _Args...> { >> + typedef typename remove_reference<_Arg>::type _Argval; >> + typedef _Res _Class::*_MemPtr; >> + typedef typename conditional< >> + is_base_of<_Class, _Argval>::value, >> + __result_of_memfun_ref<_MemPtr, _Arg, _Args...>, >> + __result_of_memfun_deref<_MemPtr, _Arg, = _Args...>>::type::type type; >> + }; >> + template > >> + struct __inv_unwrap { >> + using type =3D _Tp; >> + }; >> + template >> + struct __result_of_impl; >> + template >> + struct __result_of_impl >> + : public __result_of_memfun<__decay_t<_MemPtr>, >> + typename __inv_unwrap<_Arg>::type, = _Args...> { >> + }; >> + struct __result_of_other_impl { >> + template >> + static __result_of_success< >> + decltype(std::declval<_Fn>()(std::declval<_Args>()...)), = __invoke_other> >> + _S_test(int); >> + }; >> + template >> + struct __result_of_impl >> + : private __result_of_other_impl { >> + typedef decltype(_S_test<_Functor, _ArgTypes...>(0)) type; >> + }; >> + template >> + struct __invoke_result >> + : public __result_of_impl< >> + is_member_object_pointer< >> + typename remove_reference<_Functor>::type>::value, >> + is_member_function_pointer< >> + typename remove_reference<_Functor>::type>::value, >> + _Functor, _ArgTypes...>::type {}; >> + template >> + struct result_of<_Functor(_ArgTypes...)> >> + : public __invoke_result<_Functor, _ArgTypes...> {}; >> + template >> + using enable_if_t =3D typename enable_if<_Cond, _Tp>::type; >> + template >> + using conditional_t =3D typename conditional<_Cond, _Iftrue, = _Iffalse>::type; >> + template > + template class _Op, typename... _Args> >> + struct __detector { >> + using type =3D _Default; >> + }; >> + template class _Op, >> + typename... _Args> >> + using __detected_or =3D __detector<_Default, void, _Op, _Args...>; >> + template class _Op, >> + typename... _Args> >> + using __detected_or_t =3D typename __detected_or<_Default, _Op, = _Args...>::type; >> + template class tuple; >> + template struct __is_tuple_like_impl : false_type {}; >> + template >> + struct __is_tuple_like >> + : public __is_tuple_like_impl<__remove_cvref_t<_Tp>>::type {}; >> + namespace __swappable_details { >> + struct __do_is_swappable_impl {}; >> + struct __do_is_nothrow_swappable_impl {}; >> + } // namespace __swappable_details >> + template >> + struct __is_swappable_impl >> + : public __swappable_details::__do_is_swappable_impl {}; >> + template >> + struct is_swappable : public __is_swappable_impl<_Tp>::type { >> + static_assert( >> + std::__is_complete_or_unbounded(__type_identity<_Tp>{}), >> + "template argument must be a complete class or an unbounded = array"); >> + }; >> + template ::value, >> + typename =3D void> >> + struct __is_invocable_impl : false_type {}; >> + template >> + struct __is_invocable_impl<_Result, _Ret, true, >> + __void_t> : = true_type {}; >> + template >> + struct __is_invocable_impl<_Result, _Ret, false, >> + __void_t> { >> + private: >> + static typename _Result::type _S_get(); >> + template static void _S_conv(_Tp); >> + template (_S_get()))> >> + static true_type _S_test(int); >> + >> + public: >> + using type =3D decltype(_S_test<_Ret>(1)); >> + }; >> + template >> + struct __is_invocable >> + : __is_invocable_impl<__invoke_result<_Fn, _ArgTypes...>, = void>::type {}; >> + template >> + constexpr bool __call_is_nt(__invoke_other) { >> + return noexcept(std::declval<_Fn>()(std::declval<_Args>()...)); >> + } >> + template >> + struct __call_is_nothrow : __bool_constant( >> + typename _Result::__invoke_type{})> = {}; >> + template >> + using __call_is_nothrow_ =3D >> + __call_is_nothrow<__invoke_result<_Fn, _Args...>, _Fn, = _Args...>; >> + template >> + struct __is_nothrow_invocable >> + : __and_<__is_invocable<_Fn, _Args...>, >> + __call_is_nothrow_<_Fn, _Args...>>::type {}; >> + template >> + struct invoke_result : public __invoke_result<_Functor, = _ArgTypes...> {}; >> + template >> + using invoke_result_t =3D typename invoke_result<_Fn, = _Args...>::type; >> + template >> + struct is_invocable >> + : __is_invocable_impl<__invoke_result<_Fn, _ArgTypes...>, = void>::type {}; >> + template >> + struct is_invocable_r >> + : __is_invocable_impl<__invoke_result<_Fn, _ArgTypes...>, = _Ret>::type { >> + = static_assert(std::__is_complete_or_unbounded(__type_identity<_Fn>{}), >> + "_Ret must be a complete class or an unbounded = array"); >> + }; >> + template >> + struct is_nothrow_invocable >> + : __and_<__is_invocable_impl<__invoke_result<_Fn, = _ArgTypes...>, void>, >> + __call_is_nothrow_<_Fn, _ArgTypes...>>::type {}; >> + template >> + struct __is_nt_invocable_impl : false_type {}; >> + template >> + struct is_nothrow_invocable_r >> + : __and_<__is_nt_invocable_impl<__invoke_result<_Fn, = _ArgTypes...>, _Ret>, >> + __call_is_nothrow_<_Fn, _ArgTypes...>>::type { >> + = static_assert(std::__is_complete_or_unbounded(__type_identity<_Fn>{}), >> + "_Fn must be a complete class or an unbounded = array"); >> + static_assert( >> + = (std::__is_complete_or_unbounded(__type_identity<_ArgTypes>{}) && ...), >> + "each argument type must be a complete class or an unbounded = array"); >> + = static_assert(std::__is_complete_or_unbounded(__type_identity<_Ret>{}), >> + "_Ret must be a complete class or an unbounded = array"); >> + }; >> + template >> + inline constexpr bool is_invocable_v =3D is_invocable<_Fn, = _Args...>::value; >> + template >> + inline constexpr bool is_nothrow_invocable_v =3D >> + is_nothrow_invocable<_Fn, _Args...>::value; >> + template >> + inline constexpr bool is_invocable_r_v =3D >> + is_invocable_r<_Ret, _Fn, _Args...>::value; >> + template >> + inline constexpr bool is_nothrow_invocable_r_v =3D >> + is_nothrow_invocable_r<_Ret, _Fn, _Args...>::value; >> + template inline constexpr bool is_void_v =3D = is_void<_Tp>::value; >> + template >> + inline constexpr bool is_integral_v =3D is_integral<_Tp>::value; >> + template >> + inline constexpr bool is_lvalue_reference_v =3D = is_lvalue_reference<_Tp>::value; >> + template >> + inline constexpr bool is_reference_v =3D is_reference<_Tp>::value; >> + template >> + inline constexpr bool is_object_v =3D is_object<_Tp>::value; >> + template >> + inline constexpr bool is_constructible_v =3D >> + is_constructible<_Tp, _Args...>::value; >> + template >> + inline constexpr bool is_default_constructible_v =3D >> + is_default_constructible<_Tp>::value; >> + template >> + inline constexpr bool is_copy_constructible_v =3D >> + is_copy_constructible<_Tp>::value; >> + template >> + inline constexpr bool is_move_constructible_v =3D >> + is_move_constructible<_Tp>::value; >> + template >> + inline constexpr bool is_copy_assignable_v =3D = is_copy_assignable<_Tp>::value; >> + template >> + inline constexpr bool is_move_assignable_v =3D = is_move_assignable<_Tp>::value; >> + template >> + inline constexpr bool is_trivially_copy_constructible_v =3D >> + is_trivially_copy_constructible<_Tp>::value; >> + template >> + inline constexpr bool is_trivially_move_constructible_v =3D >> + is_trivially_move_constructible<_Tp>::value; >> + template >> + inline constexpr bool is_trivially_copy_assignable_v =3D >> + is_trivially_copy_assignable<_Tp>::value; >> + template >> + inline constexpr bool is_trivially_move_assignable_v =3D >> + is_trivially_move_assignable<_Tp>::value; >> + template >> + inline constexpr bool is_trivially_destructible_v =3D >> + is_trivially_destructible<_Tp>::value; >> + template >> + inline constexpr bool is_nothrow_default_constructible_v =3D >> + is_nothrow_default_constructible<_Tp>::value; >> + template >> + inline constexpr bool is_nothrow_destructible_v =3D >> + is_nothrow_destructible<_Tp>::value; >> + template >> + inline constexpr bool is_same_v =3D __is_same(_Tp, _Up); >> + template >> + inline constexpr bool is_convertible_v =3D is_convertible<_From, = _To>::value; >> + template >> + struct has_unique_object_representations >> + : bool_constant<__has_unique_object_representations( >> + remove_cv_t>)> {}; >> + template using remove_cvref_t =3D = __remove_cvref_t<_Tp>; >> + constexpr inline bool is_constant_evaluated() noexcept { >> + return __builtin_is_constant_evaluated(); >> + } >> + template struct common_reference; >> + template >> + using common_reference_t =3D typename = common_reference<_Tp...>::type; >> +} // namespace ) >> +namespace std __attribute__((__visibility__("default"))) { >> + template >> + [[__nodiscard__]] constexpr _Tp &&forward( >> + typename std::remove_reference<_Tp>::type & __t) noexcept { >> + return static_cast<_Tp &&>(__t); >> + } >> + template >> + [[__nodiscard__]] constexpr typename = std::remove_reference<_Tp>::type &&move( >> + _Tp && __t) noexcept { >> + return static_cast::type = &&>(__t); >> + }; >> + template >> + [[__nodiscard__]] inline constexpr _Tp *addressof(_Tp & __r) = noexcept {} >> +} // namespace ) >> +extern "C++" { >> +namespace std __attribute__((__visibility__("default"))) { >> + template struct __is_integer { >> + enum { __value =3D 0 }; >> + }; >> + template struct iterator_traits; >> + template struct = __is_nonvolatile_trivially_copyable; >> +} // namespace ) >> +} >> +namespace __gnu_cxx __attribute__((__visibility__("default"))) { >> + template >> + struct __is_integer_nonstrict : public std::__is_integer<_Tp> { >> + using std::__is_integer<_Tp>::__value; >> + enum { __width =3D __value ? sizeof(_Tp) * 8 : 0 }; >> + }; >> + template struct __numeric_traits_integer { >> + static const bool __is_signed =3D (_Value)(-1) < 0; >> + static const int __digits =3D >> + __is_integer_nonstrict<_Value>::__width - __is_signed; >> + }; >> + template using __int_traits =3D = __numeric_traits_integer<_Tp>; >> +} // namespace ) >> +namespace std __attribute__((__visibility__("default"))) { >> + namespace __detail { >> + template >> + concept __same_as =3D std::is_same_v<_Tp, _Up>; >> + } >> + template >> + concept same_as =3D >> + __detail::__same_as<_Tp, _Up> && __detail::__same_as<_Up, = _Tp>; >> + template >> + concept derived_from =3D >> + __is_base_of(_Base, _Derived) && >> + is_convertible_v; >> + template >> + concept convertible_to =3D is_convertible_v<_From, _To> && >> + requires(add_rvalue_reference_t<_From>(&__f)()) { >> + static_cast<_To>(__f()); >> + }; >> + template >> + concept common_reference_with =3D >> + same_as, common_reference_t<_Up, = _Tp>> && >> + convertible_to<_Tp, common_reference_t<_Tp, _Up>> && >> + convertible_to<_Up, common_reference_t<_Tp, _Up>>; >> + namespace __detail { >> + template using __cref =3D const = remove_reference_t<_Tp> &; >> + } >> + template >> + concept assignable_from =3D is_lvalue_reference_v<_Lhs> && >> + common_reference_with<__detail::__cref<_Lhs>, = __detail::__cref<_Rhs>> && >> + requires(_Lhs __lhs, _Rhs && __rhs) { >> + { __lhs =3D static_cast<_Rhs &&>(__rhs) } -> same_as<_Lhs>; >> + }; >> + template >> + concept destructible =3D is_nothrow_destructible_v<_Tp>; >> + template >> + concept constructible_from =3D >> + destructible<_Tp> && is_constructible_v<_Tp, _Args...>; >> + template >> + concept default_initializable =3D constructible_from<_Tp> && = requires { >> + _Tp{}; >> + }; >> + template >> + concept move_constructible =3D >> + constructible_from<_Tp, _Tp> && convertible_to<_Tp, _Tp>; >> + template >> + concept copy_constructible =3D >> + move_constructible<_Tp> && constructible_from<_Tp, _Tp &> && >> + convertible_to<_Tp &, _Tp> && constructible_from<_Tp, const = _Tp &> && >> + convertible_to && constructible_from<_Tp, = const _Tp> && >> + convertible_to; >> + namespace ranges { >> + namespace __cust_swap { >> + struct _Swap {}; >> + } // namespace __cust_swap >> + inline namespace __cust { >> + inline constexpr __cust_swap::_Swap swap; >> + } >> + } // namespace ranges >> + template >> + concept swappable =3D requires(_Tp & __a, _Tp & __b) { >> + ranges::swap(__a, __b); >> + }; >> + template >> + concept movable =3D is_object_v<_Tp> && move_constructible<_Tp> && >> + assignable_from<_Tp &, _Tp> && swappable<_Tp>; >> + template >> + concept copyable =3D copy_constructible<_Tp> && movable<_Tp> && >> + assignable_from<_Tp &, _Tp &> && assignable_from<_Tp &, const = _Tp &> && >> + assignable_from<_Tp &, const _Tp>; >> + template >> + concept semiregular =3D copyable<_Tp> && = default_initializable<_Tp>; >> + namespace __detail { >> + template >> + concept __boolean_testable_impl =3D convertible_to<_Tp, bool>; >> + template >> + concept __boolean_testable =3D >> + __boolean_testable_impl<_Tp> && requires(_Tp && __t) { >> + { !static_cast<_Tp &&>(__t) } -> __boolean_testable_impl; >> + }; >> + } // namespace __detail >> + namespace __detail { >> + template >> + concept __weakly_eq_cmp_with =3D requires(__detail::__cref<_Tp> = __t, >> + __detail::__cref<_Up> __u) = { >> + { __t =3D=3D __u } -> __boolean_testable; >> + }; >> + } // namespace __detail >> + template >> + concept equality_comparable =3D = __detail::__weakly_eq_cmp_with<_Tp, _Tp>; >> + namespace __detail { >> + template >> + concept __partially_ordered_with =3D >> + requires(const remove_reference_t<_Tp> &__t, >> + const remove_reference_t<_Up> &__u) { >> + { __t < __u } -> __boolean_testable; >> + }; >> + } // namespace __detail >> + template >> + concept regular =3D semiregular<_Tp> && equality_comparable<_Tp>; >> + template >> + concept invocable =3D is_invocable_v<_Fn, _Args...>; >> + namespace __cmp_cat {} >> + template class __pair_base; >> + template >> + struct pair : private __pair_base<_T1, _T2> {}; >> + template struct __replace_first_arg; >> + template