Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add missing implicit SFINAE constraints #2607

Merged
merged 13 commits into from
Mar 19, 2022
6 changes: 4 additions & 2 deletions stl/inc/any
Original file line number Diff line number Diff line change
Expand Up @@ -357,11 +357,13 @@ inline void swap(any& _Left, any& _Right) noexcept {
_Left.swap(_Right);
}

template <class _ValueType, class... _Types>
template <class _ValueType, class... _Types,
enable_if_t<is_constructible_v<any, in_place_type_t<_ValueType>, _Types...>, int> = 0>
StephanTLavavej marked this conversation as resolved.
Show resolved Hide resolved
_NODISCARD any make_any(_Types&&... _Args) { // construct an any containing a _ValueType initialized with _Args...
return any{in_place_type<_ValueType>, _STD forward<_Types>(_Args)...};
}
template <class _ValueType, class _Elem, class... _Types>
template <class _ValueType, class _Elem, class... _Types,
enable_if_t<is_constructible_v<any, in_place_type_t<_ValueType>, initializer_list<_Elem>&, _Types...>, int> = 0>
_NODISCARD any make_any(initializer_list<_Elem> _Ilist, _Types&&... _Args) {
// construct an any containing a _ValueType initialized with _Ilist and _Args...
return any{in_place_type<_ValueType>, _Ilist, _STD forward<_Types>(_Args)...};
Expand Down
32 changes: 22 additions & 10 deletions stl/inc/memory
Original file line number Diff line number Diff line change
Expand Up @@ -1623,7 +1623,7 @@ public:
return *this;
}

template <class _Ty2>
template <class _Ty2, enable_if_t<_SP_pointer_compatible<_Ty2, _Ty>::value, int> = 0>
shared_ptr& operator=(const shared_ptr<_Ty2>& _Right) noexcept {
shared_ptr(_Right).swap(*this);
return *this;
Expand All @@ -1634,21 +1634,24 @@ public:
return *this;
}

template <class _Ty2>
template <class _Ty2, enable_if_t<_SP_pointer_compatible<_Ty2, _Ty>::value, int> = 0>
shared_ptr& operator=(shared_ptr<_Ty2>&& _Right) noexcept { // take resource from _Right
shared_ptr(_STD move(_Right)).swap(*this);
return *this;
}

#if _HAS_AUTO_PTR_ETC
template <class _Ty2>
template <class _Ty2, enable_if_t<is_convertible_v<_Ty2*, _Ty*>, int> = 0>
shared_ptr& operator=(auto_ptr<_Ty2>&& _Right) {
shared_ptr(_STD move(_Right)).swap(*this);
return *this;
}
#endif // _HAS_AUTO_PTR_ETC

template <class _Ux, class _Dx>
template <class _Ux, class _Dx,
enable_if_t<conjunction_v<_SP_pointer_compatible<_Ux, _Ty>,
is_convertible<typename unique_ptr<_Ux, _Dx>::pointer, element_type*>>,
int> = 0>
shared_ptr& operator=(unique_ptr<_Ux, _Dx>&& _Right) { // move from unique_ptr
shared_ptr(_STD move(_Right)).swap(*this);
return *this;
Expand All @@ -1662,17 +1665,26 @@ public:
shared_ptr().swap(*this);
}

template <class _Ux>
template <class _Ux,
enable_if_t<conjunction_v<conditional_t<is_array_v<_Ty>, _Can_array_delete<_Ux>, _Can_scalar_delete<_Ux>>,
_SP_convertible<_Ux, _Ty>>,
int> = 0>
void reset(_Ux* _Px) { // release, take ownership of _Px
shared_ptr(_Px).swap(*this);
}

template <class _Ux, class _Dx>
template <class _Ux, class _Dx,
enable_if_t<conjunction_v<is_move_constructible<_Dx>, _Can_call_function_object<_Dx&, _Ux*&>,
_SP_convertible<_Ux, _Ty>>,
int> = 0>
void reset(_Ux* _Px, _Dx _Dt) { // release, take ownership of _Px, with deleter _Dt
shared_ptr(_Px, _Dt).swap(*this);
}

template <class _Ux, class _Dx, class _Alloc>
template <class _Ux, class _Dx, class _Alloc,
enable_if_t<conjunction_v<is_move_constructible<_Dx>, _Can_call_function_object<_Dx&, _Ux*&>,
_SP_convertible<_Ux, _Ty>>,
int> = 0>
void reset(_Ux* _Px, _Dx _Dt, _Alloc _Ax) { // release, take ownership of _Px, with deleter _Dt, allocator _Ax
shared_ptr(_Px, _Dt, _Ax).swap(*this);
}
Expand Down Expand Up @@ -3023,7 +3035,7 @@ public:
return *this;
}

template <class _Ty2>
template <class _Ty2, enable_if_t<_SP_pointer_compatible<_Ty2, _Ty>::value, int> = 0>
weak_ptr& operator=(const weak_ptr<_Ty2>& _Right) noexcept {
weak_ptr(_Right).swap(*this);
return *this;
Expand All @@ -3034,13 +3046,13 @@ public:
return *this;
}

template <class _Ty2>
template <class _Ty2, enable_if_t<_SP_pointer_compatible<_Ty2, _Ty>::value, int> = 0>
weak_ptr& operator=(weak_ptr<_Ty2>&& _Right) noexcept {
weak_ptr(_STD move(_Right)).swap(*this);
return *this;
}

template <class _Ty2>
template <class _Ty2, enable_if_t<_SP_pointer_compatible<_Ty2, _Ty>::value, int> = 0>
weak_ptr& operator=(const shared_ptr<_Ty2>& _Right) noexcept {
weak_ptr(_Right).swap(*this);
return *this;
Expand Down
7 changes: 4 additions & 3 deletions stl/inc/optional
Original file line number Diff line number Diff line change
Expand Up @@ -853,15 +853,16 @@ _CONSTEXPR20 void swap(optional<_Ty>& _Left, optional<_Ty>& _Right) noexcept(noe
_Left.swap(_Right);
}

template <class _Ty>
template <class _Ty, enable_if_t<is_constructible_v<decay_t<_Ty>, _Ty>, int> = 0> // LWG-3627
_NODISCARD constexpr optional<decay_t<_Ty>> make_optional(_Ty&& _Value) {
return optional<decay_t<_Ty>>{_STD forward<_Ty>(_Value)};
}
template <class _Ty, class... _Types>
template <class _Ty, class... _Types, enable_if_t<is_constructible_v<_Ty, _Types...>, int> = 0>
_NODISCARD constexpr optional<_Ty> make_optional(_Types&&... _Args) {
return optional<_Ty>{in_place, _STD forward<_Types>(_Args)...};
}
template <class _Ty, class _Elem, class... _Types>
template <class _Ty, class _Elem, class... _Types,
enable_if_t<is_constructible_v<_Ty, initializer_list<_Elem>&, _Types...>, int> = 0>
_NODISCARD constexpr optional<_Ty> make_optional(initializer_list<_Elem> _Ilist, _Types&&... _Args) {
return optional<_Ty>{in_place, _Ilist, _STD forward<_Types>(_Args)...};
}
Expand Down
1 change: 1 addition & 0 deletions tests/std/test.lst
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@ tests\GH_002030_asan_annotate_vector
tests\GH_002039_byte_is_not_trivially_swappable
tests\GH_002058_debug_iterator_race
tests\GH_002120_streambuf_seekpos_and_seekoff
tests\GH_002299_implicit_sfinae_constraints
tests\GH_002488_promise_not_default_constructible_types
tests\LWG2597_complex_branch_cut
tests\LWG3018_shared_ptr_function
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Copyright (c) Microsoft Corporation.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

RUNALL_INCLUDE ..\usual_matrix.lst
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
// Copyright (c) Microsoft Corporation.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#include <memory>
#include <type_traits>
#include <utility>

#if _HAS_CXX17
#include <any>
#include <initializer_list>
#include <optional>
#endif // _HAS_CXX17

#define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__)

using namespace std;

// tests for shared_ptr<T>::operator=
template <class T, class U, class = void>
constexpr bool can_shared_ptr_assign = false;

template <class T, class U>
constexpr bool can_shared_ptr_assign<T, U, void_t<decltype(declval<shared_ptr<T>&>() = declval<U>())>> = true;
StephanTLavavej marked this conversation as resolved.
Show resolved Hide resolved

STATIC_ASSERT(can_shared_ptr_assign<int, shared_ptr<int>>);
STATIC_ASSERT(!can_shared_ptr_assign<int, shared_ptr<long>>);
STATIC_ASSERT(!can_shared_ptr_assign<int, const shared_ptr<long>&>);
STATIC_ASSERT(!can_shared_ptr_assign<int, unique_ptr<long>>);
#if _HAS_AUTO_PTR_ETC
STATIC_ASSERT(!can_shared_ptr_assign<int, auto_ptr<long>>);
#endif
StephanTLavavej marked this conversation as resolved.
Show resolved Hide resolved

// tests for shared_ptr<T>::reset
template <class Void, class T, class... Us>
constexpr bool can_shared_ptr_reset_impl = false;

template <class T, class... Us>
constexpr bool
can_shared_ptr_reset_impl<void_t<decltype(declval<shared_ptr<T>&>().reset(declval<Us>()...))>, T, Us...> = true;

template <class T, class... Us>
constexpr bool can_shared_ptr_reset = can_shared_ptr_reset_impl<void, T, Us...>;

STATIC_ASSERT(can_shared_ptr_reset<int, int*>);
STATIC_ASSERT(!can_shared_ptr_reset<int, long*>);
STATIC_ASSERT(!can_shared_ptr_reset<int, long*, default_delete<long>>);
STATIC_ASSERT(!can_shared_ptr_reset<int, long*, default_delete<long>, allocator<long>>);

// tests for weak_ptr<T>::operator=
template <class T, class U, class = void>
constexpr bool can_weak_ptr_assign = false;

template <class T, class U>
constexpr bool can_weak_ptr_assign<T, U, void_t<decltype(declval<weak_ptr<T>&>() = declval<U>())>> = true;

STATIC_ASSERT(can_weak_ptr_assign<int, weak_ptr<int>>);
STATIC_ASSERT(!can_weak_ptr_assign<int, weak_ptr<long>>);
STATIC_ASSERT(!can_weak_ptr_assign<int, const weak_ptr<long>&>);
STATIC_ASSERT(!can_weak_ptr_assign<int, const shared_ptr<long>&>);

#if _HAS_CXX17
// tests for make_optional
template <class T, class = void>
constexpr bool can_make_optional_decay = false;

template <class T>
constexpr bool can_make_optional_decay<T, void_t<decltype(make_optional(declval<T>()))>> = true;

template <class Void, class T, class... Us>
constexpr bool can_make_optional_impl = false;

template <class T, class... Us>
constexpr bool can_make_optional_impl<void_t<decltype(make_optional<T>(declval<Us>()...))>, T, Us...> = true;

template <class T, class... Us>
constexpr bool can_make_optional_usual = can_make_optional_impl<void, T, Us...>;

STATIC_ASSERT(can_make_optional_decay<unique_ptr<int>>);
STATIC_ASSERT(!can_make_optional_decay<const unique_ptr<int>&>); // LWG-3627
STATIC_ASSERT(can_make_optional_usual<int, int>);
STATIC_ASSERT(!can_make_optional_usual<int, int, int>);
STATIC_ASSERT(!can_make_optional_usual<int, initializer_list<int>&>);
StephanTLavavej marked this conversation as resolved.
Show resolved Hide resolved

// tests for make_any
template <class Void, class T, class... Us>
constexpr bool can_make_any_impl = false;

template <class T, class... Us>
constexpr bool can_make_any_impl<void_t<decltype(make_any<T>(declval<Us>()...))>, T, Us...> = true;

template <class T, class... Us>
constexpr bool can_make_any = can_make_any_impl<void, T, Us...>;

STATIC_ASSERT(can_make_any<int, int>);
STATIC_ASSERT(!can_make_any<unique_ptr<int>, const unique_ptr<int>&>);
STATIC_ASSERT(!can_make_any<int, int, int>);
STATIC_ASSERT(!can_make_any<int, initializer_list<int>&>);
#endif // _HAS_CXX17

int main() {} // COMPILE-ONLY