Skip to content

Commit

Permalink
Implement P2655R3 common_reference_t Of reference_wrapper Should …
Browse files Browse the repository at this point in the history
…Be A Reference Type (#3513)

Co-authored-by: Stephan T. Lavavej <[email protected]>
  • Loading branch information
frederick-vs-ja and StephanTLavavej authored Mar 3, 2023
1 parent efd50e8 commit ec7cc0f
Show file tree
Hide file tree
Showing 5 changed files with 144 additions and 65 deletions.
10 changes: 0 additions & 10 deletions stl/inc/concepts
Original file line number Diff line number Diff line change
Expand Up @@ -39,16 +39,6 @@ _EXPORT_STD template <class _Derived, class _Base>
concept derived_from = __is_base_of(_Base, _Derived)
&& __is_convertible_to(const volatile _Derived*, const volatile _Base*);

_EXPORT_STD template <class _From, class _To>
#if !defined(__EDG__) && !defined(__clang__) // TRANSITION, DevCom-1627396
concept convertible_to = is_convertible_v<_From, _To>
#else // ^^^ workaround / no workaround vvv
concept convertible_to = __is_convertible_to(_From, _To)
#endif // ^^^ no workaround ^^^
&& requires {
static_cast<_To>(_STD declval<_From>());
};

template <class _From, class _To>
concept _Implicitly_convertible_to = is_convertible_v<_From, _To>;

Expand Down
102 changes: 73 additions & 29 deletions stl/inc/type_traits
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ using add_rvalue_reference_t = typename _Add_reference<_Ty>::_Rvalue;

_EXPORT_STD template <class _Ty>
add_rvalue_reference_t<_Ty> declval() noexcept {
static_assert(_Always_false<_Ty>, "Calling declval is ill-formed, see N4917 22.2.6 [declval]/2.");
static_assert(_Always_false<_Ty>, "Calling declval is ill-formed, see N4928 [declval]/2.");
}

_EXPORT_STD template <class _Ty>
Expand Down Expand Up @@ -1201,8 +1201,8 @@ using _Conditional_type = decltype(false ? _STD declval<_Ty1>() : _STD declval<_
template <class _Ty1, class _Ty2, class = void>
struct _Const_lvalue_cond_oper {};

// N4917 21.3.8.7 [meta.trans.other]/3.3.4 (per the proposed resolution of LWG-3205): "Otherwise, if
// remove_cvref_t</**/> denotes a type..."
// N4928 [meta.trans.other]/3.3.4 (per the proposed resolution of LWG-3205): "Otherwise, if remove_cvref_t</**/> denotes
// a type..."
template <class _Ty1, class _Ty2>
struct _Const_lvalue_cond_oper<_Ty1, _Ty2, void_t<_Conditional_type<const _Ty1&, const _Ty2&>>> {
using type = remove_cvref_t<_Conditional_type<const _Ty1&, const _Ty2&>>;
Expand Down Expand Up @@ -1279,11 +1279,11 @@ struct _Copy_cv_impl<const volatile _From> {
using _Apply = const volatile _To;
};
template <class _From, class _To>
using _Copy_cv = // N4917 21.3.8.7 [meta.trans.other]/2.3
using _Copy_cv = // N4928 [meta.trans.other]/2.3
typename _Copy_cv_impl<_From>::template _Apply<_To>;

template <class _Ty1>
struct _Add_qualifiers { // _Add_qualifiers<A>::template _Apply is XREF(A) from N4917 21.3.8.7 [meta.trans.other]/2.2
struct _Add_qualifiers { // _Add_qualifiers<A>::template _Apply is XREF(A) from N4928 [meta.trans.other]/2.2
template <class _Ty2>
using _Apply = _Copy_cv<_Ty1, _Ty2>;
};
Expand All @@ -1300,7 +1300,7 @@ struct _Add_qualifiers<_Ty1&&> {

#if !defined(__EDG__) && !defined(__clang__) // TRANSITION, DevCom-10095944
template <class _Ty1, class _Ty2>
using _Cond_res_if_right = // N4917 21.3.8.7 [meta.trans.other]/2.4
using _Cond_res_if_right = // N4928 [meta.trans.other]/2.4
decltype(false ? _Returns_exactly<_Ty1>() : _Returns_exactly<_Ty2>());

template <class _Ty>
Expand All @@ -1322,7 +1322,7 @@ template <class _Ty1, class _Ty2>
using _Cond_res = typename _Cond_res_workaround<_Ty1, _Ty2>::type;
#else // ^^^ workaround / no workaround vvv
template <class _Ty1, class _Ty2>
using _Cond_res = // N4917 21.3.8.7 [meta.trans.other]/2.4
using _Cond_res = // N4928 [meta.trans.other]/2.4
decltype(false ? _Returns_exactly<_Ty1>() : _Returns_exactly<_Ty2>());
#endif // ^^^ no workaround ^^^

Expand All @@ -1332,30 +1332,30 @@ struct common_reference;
_EXPORT_STD template <class... _Types>
using common_reference_t = typename common_reference<_Types...>::type;

// N4917 21.3.8.7 [meta.trans.other]/5.1: "If sizeof...(T) is zero ..."
// N4928 [meta.trans.other]/5.1: "If sizeof...(T) is zero ..."
template <>
struct common_reference<> {};

// N4917 21.3.8.7 [meta.trans.other]/5.2: "...if sizeof...(T) is one ..."
// N4928 [meta.trans.other]/5.2: "...if sizeof...(T) is one ..."
template <class _Ty>
struct common_reference<_Ty> {
using type = _Ty;
};

// N4917 21.3.8.7 [meta.trans.other]/5.3: "...if sizeof...(T) is two..."
// N4928 [meta.trans.other]/5.3: "...if sizeof...(T) is two..."

// N4917 21.3.8.7 [meta.trans.other]/5.3.4: "if common_type_t<T1, T2> is well-formed..."
// N4917 21.3.8.7 [meta.trans.other]/5.3.5: "Otherwise, there shall be no member type."
// N4928 [meta.trans.other]/5.3.4: "if common_type_t<T1, T2> is well-formed..."
// N4928 [meta.trans.other]/5.3.5: "Otherwise, there shall be no member type."
template <class _Ty1, class _Ty2, class = void>
struct _Common_reference2C : common_type<_Ty1, _Ty2> {};

// N4917 21.3.8.7 [meta.trans.other]/5.3.3: "if COND_RES(T1, T2) is well-formed..."
// N4928 [meta.trans.other]/5.3.3: "if COND_RES(T1, T2) is well-formed..."
template <class _Ty1, class _Ty2>
struct _Common_reference2C<_Ty1, _Ty2, void_t<_Cond_res<_Ty1, _Ty2>>> {
using type = _Cond_res<_Ty1, _Ty2>;
};

// N4917 21.3.8.7 [meta.trans.other]/5.3.2: "if basic_common_reference<[...]>::type is well-formed..."
// N4928 [meta.trans.other]/5.3.2: "if basic_common_reference<[...]>::type is well-formed..."
template <class _Ty1, class _Ty2>
using _Basic_specialization = typename basic_common_reference<remove_cvref_t<_Ty1>, remove_cvref_t<_Ty2>,
_Add_qualifiers<_Ty1>::template _Apply, _Add_qualifiers<_Ty2>::template _Apply>::type;
Expand All @@ -1368,45 +1368,59 @@ struct _Common_reference2B<_Ty1, _Ty2, void_t<_Basic_specialization<_Ty1, _Ty2>>
using type = _Basic_specialization<_Ty1, _Ty2>;
};

// N4917 21.3.8.7 [meta.trans.other]/5.3.1: "If T1 and T2 are reference types and COMMON_REF(T1, T2) is well-formed..."
// N4928 [meta.trans.other]/5.3.1 as updated by P2655R3 (TRANSITION, cite new WP here):
// "Let R be COMMON-REF(T1, T2). If T1 and T2 are reference types, R is well-formed, and
// is_convertible_v<add_pointer_t<T1>, add_pointer_t<R>> && is_convertible_v<add_pointer_t<T2>, add_pointer_t<R>>
// is true, then the member typedef type denotes R."
template <class _Ty1, class _Ty2, class = void>
struct _Common_reference2A : _Common_reference2B<_Ty1, _Ty2> {};

template <class _Ty1, class _Ty2, class _Result = _Cond_res<_Copy_cv<_Ty1, _Ty2>&, _Copy_cv<_Ty2, _Ty1>&>,
enable_if_t<is_lvalue_reference_v<_Result>, int> = 0>
using _LL_common_ref = _Result;

template <class _Ty1, class _Ty2, class = void>
struct _Common_reference2AX {};

template <class _Ty1, class _Ty2>
struct _Common_reference2A<_Ty1&, _Ty2&, void_t<_LL_common_ref<_Ty1, _Ty2>>> {
using type = _LL_common_ref<_Ty1, _Ty2>; // "both lvalues" case from N4917 21.3.8.7 [meta.trans.other]/2.5
struct _Common_reference2AX<_Ty1&, _Ty2&, void_t<_LL_common_ref<_Ty1, _Ty2>>> {
using type = _LL_common_ref<_Ty1, _Ty2>; // "both lvalues" case from N4928 [meta.trans.other]/2.5
};

template <class _Ty1, class _Ty2>
struct _Common_reference2A<_Ty1&&, _Ty2&, enable_if_t<is_convertible_v<_Ty1&&, _LL_common_ref<const _Ty1, _Ty2>>>> {
using type =
_LL_common_ref<const _Ty1, _Ty2>; // "rvalue and lvalue" case from N4917 21.3.8.7 [meta.trans.other]/2.7
struct _Common_reference2AX<_Ty1&&, _Ty2&, enable_if_t<is_convertible_v<_Ty1&&, _LL_common_ref<const _Ty1, _Ty2>>>> {
using type = _LL_common_ref<const _Ty1, _Ty2>; // "rvalue and lvalue" case from N4928 [meta.trans.other]/2.7
};

template <class _Ty1, class _Ty2>
struct _Common_reference2A<_Ty1&, _Ty2&&, enable_if_t<is_convertible_v<_Ty2&&, _LL_common_ref<const _Ty2, _Ty1>>>> {
using type =
_LL_common_ref<const _Ty2, _Ty1>; // "lvalue and rvalue" case from N4917 21.3.8.7 [meta.trans.other]/2.8
struct _Common_reference2AX<_Ty1&, _Ty2&&, enable_if_t<is_convertible_v<_Ty2&&, _LL_common_ref<const _Ty2, _Ty1>>>> {
using type = _LL_common_ref<const _Ty2, _Ty1>; // "lvalue and rvalue" case from N4928 [meta.trans.other]/2.8
};

template <class _Ty1, class _Ty2>
using _RR_common_ref = remove_reference_t<_LL_common_ref<_Ty1, _Ty2>>&&;

template <class _Ty1, class _Ty2>
struct _Common_reference2A<_Ty1&&, _Ty2&&,
struct _Common_reference2AX<_Ty1&&, _Ty2&&,
enable_if_t<is_convertible_v<_Ty1&&, _RR_common_ref<_Ty1, _Ty2>>
&& is_convertible_v<_Ty2&&, _RR_common_ref<_Ty1, _Ty2>>>> {
using type = _RR_common_ref<_Ty1, _Ty2>; // "both rvalues" case from N4917 21.3.8.7 [meta.trans.other]/2.6
using type = _RR_common_ref<_Ty1, _Ty2>; // "both rvalues" case from N4928 [meta.trans.other]/2.6
};

template <class _Ty1, class _Ty2>
using _Common_ref_2AX_t = typename _Common_reference2AX<_Ty1, _Ty2>::type;

template <class _Ty1, class _Ty2>
struct _Common_reference2A<_Ty1, _Ty2,
enable_if_t<is_convertible_v<add_pointer_t<_Ty1>, add_pointer_t<_Common_ref_2AX_t<_Ty1, _Ty2>>>
&& is_convertible_v<add_pointer_t<_Ty2>, add_pointer_t<_Common_ref_2AX_t<_Ty1, _Ty2>>>>> {
using type = _Common_ref_2AX_t<_Ty1, _Ty2>;
};

template <class _Ty1, class _Ty2>
struct common_reference<_Ty1, _Ty2> : _Common_reference2A<_Ty1, _Ty2> {};

// N4917 21.3.8.7 [meta.trans.other]/5.4: "if sizeof...(T) is greater than two..."
// N4928 [meta.trans.other]/5.4: "if sizeof...(T) is greater than two..."
template <class _Void, class _Ty1, class _Ty2, class... _Types>
struct _Fold_common_reference {};
template <class _Ty1, class _Ty2, class... _Types>
Expand Down Expand Up @@ -1461,9 +1475,8 @@ _EXPORT_STD template <class _Ty>
class reference_wrapper;

// std::invoke isn't constexpr in C++17, and normally implementers are forbidden from "strengthening" constexpr
// (WG21-N4917 16.4.6.7 [constexpr.functions]/1), yet both std::apply and std::visit are required to be constexpr and
// have invoke-like behavior. As a result, we've chosen to apply the part of P1065R2 resolving LWG-2894 as a defect
// report.
// (N4928 [constexpr.functions]/1), yet both std::apply and std::visit are required to be constexpr and have
// invoke-like behavior. As a result, we've chosen to apply the part of P1065R2 resolving LWG-2894 as a defect report.

enum class _Invoker_strategy {
_Functor,
Expand Down Expand Up @@ -2082,6 +2095,37 @@ struct _Is_trivially_swappable : bool_constant<_Is_trivially_swappable_v<_Ty>> {
// true_type if and only if it is valid to swap two _Ty lvalues by exchanging object representations.
};

#ifdef __cpp_lib_concepts // TRANSITION, GH-395
_EXPORT_STD template <class _From, class _To>
concept convertible_to =
#if !defined(__EDG__) && !defined(__clang__) // TRANSITION, DevCom-1627396
is_convertible_v<_From, _To>
#else // ^^^ workaround / no workaround vvv
__is_convertible_to(_From, _To)
#endif // ^^^ no workaround ^^^
&& requires { static_cast<_To>(_STD declval<_From>()); };

template <class _RefWrap, class _Ty, class _RefWrapQ, class _TyQ>
concept _Ref_wrap_common_reference_exists_with =
_Is_specialization_v<_RefWrap, reference_wrapper>
&& requires { typename common_reference_t<typename _RefWrap::type&, _TyQ>; }
&& convertible_to<_RefWrapQ, common_reference_t<typename _RefWrap::type&, _TyQ>>;

template <class _RefWrap, class _Ty, template <class> class _RefWrapQual, template <class> class _TyQual>
requires (_Ref_wrap_common_reference_exists_with<_RefWrap, _Ty, _RefWrapQual<_RefWrap>, _TyQual<_Ty>>
&& !_Ref_wrap_common_reference_exists_with<_Ty, _RefWrap, _TyQual<_Ty>, _RefWrapQual<_RefWrap>>)
struct basic_common_reference<_RefWrap, _Ty, _RefWrapQual, _TyQual> {
using type = common_reference_t<typename _RefWrap::type&, _TyQual<_Ty>>;
};

template <class _Ty, class _RefWrap, template <class> class _TyQual, template <class> class _RefWrapQual>
requires (_Ref_wrap_common_reference_exists_with<_RefWrap, _Ty, _RefWrapQual<_RefWrap>, _TyQual<_Ty>>
&& !_Ref_wrap_common_reference_exists_with<_Ty, _RefWrap, _TyQual<_Ty>, _RefWrapQual<_RefWrap>>)
struct basic_common_reference<_Ty, _RefWrap, _TyQual, _RefWrapQual> {
using type = common_reference_t<typename _RefWrap::type&, _TyQual<_Ty>>;
};
#endif // __cpp_lib_concepts

#define _BITMASK_OPS(_MAYBE_EXPORT, _BITMASK) \
_MAYBE_EXPORT _NODISCARD constexpr _BITMASK operator&(_BITMASK _Left, _BITMASK _Right) noexcept { \
using _IntTy = _STD underlying_type_t<_BITMASK>; \
Expand Down
35 changes: 21 additions & 14 deletions stl/inc/yvals_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,7 @@
// P2588R3 barrier's Phase Completion Guarantees
// P2602R2 Poison Pills Are Too Toxic
// P2609R3 Relaxing Ranges Just A Smidge
// P2655R3 common_reference_t Of reference_wrapper Should Be A Reference Type
// P2711R1 Making Multi-Param Constructors Of Views explicit

// _HAS_CXX20 indirectly controls:
Expand Down Expand Up @@ -1611,20 +1612,26 @@ _EMIT_STL_ERROR(STL1004, "C++98 unexpected() is incompatible with C++23 unexpect
#define __cpp_lib_bit_cast 201806L
#define __cpp_lib_bitops 201907L
#define __cpp_lib_bounded_array_traits 201902L
#define __cpp_lib_constexpr_algorithms 201806L
#define __cpp_lib_constexpr_complex 201711L
#define __cpp_lib_constexpr_dynamic_alloc 201907L
#define __cpp_lib_constexpr_functional 201907L
#define __cpp_lib_constexpr_iterator 201811L
#define __cpp_lib_constexpr_numeric 201911L
#define __cpp_lib_constexpr_string 201907L
#define __cpp_lib_constexpr_string_view 201811L
#define __cpp_lib_constexpr_tuple 201811L
#define __cpp_lib_constexpr_utility 201811L
#define __cpp_lib_constexpr_vector 201907L
#define __cpp_lib_destroying_delete 201806L
#define __cpp_lib_endian 201907L
#define __cpp_lib_erase_if 202002L

#ifdef __cpp_lib_concepts
#define __cpp_lib_common_reference 202302L
#define __cpp_lib_common_reference_wrapper 202302L
#endif // __cpp_lib_concepts

#define __cpp_lib_constexpr_algorithms 201806L
#define __cpp_lib_constexpr_complex 201711L
#define __cpp_lib_constexpr_dynamic_alloc 201907L
#define __cpp_lib_constexpr_functional 201907L
#define __cpp_lib_constexpr_iterator 201811L
#define __cpp_lib_constexpr_numeric 201911L
#define __cpp_lib_constexpr_string 201907L
#define __cpp_lib_constexpr_string_view 201811L
#define __cpp_lib_constexpr_tuple 201811L
#define __cpp_lib_constexpr_utility 201811L
#define __cpp_lib_constexpr_vector 201907L
#define __cpp_lib_destroying_delete 201806L
#define __cpp_lib_endian 201907L
#define __cpp_lib_erase_if 202002L

#ifdef __cpp_lib_concepts
#define __cpp_lib_format 202207L
Expand Down
Loading

0 comments on commit ec7cc0f

Please sign in to comment.