Skip to content

Commit

Permalink
Add missing implicit SFINAE constraints (#2607)
Browse files Browse the repository at this point in the history
Co-authored-by: Stephan T. Lavavej <[email protected]>
  • Loading branch information
frederick-vs-ja and StephanTLavavej authored Mar 19, 2022
1 parent fdcafc0 commit f099e9c
Show file tree
Hide file tree
Showing 6 changed files with 135 additions and 15 deletions.
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>
_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\GH_002581_common_reference_workaround
tests\LWG2597_complex_branch_cut
Expand Down
4 changes: 4 additions & 0 deletions tests/std/tests/GH_002299_implicit_sfinae_constraints/env.lst
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;

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

// 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>&>);

// 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

0 comments on commit f099e9c

Please sign in to comment.