D4451: Fix copy/move issues casude by __tuple_leafs's converting constructor
git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@213888 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
@@ -27,6 +27,32 @@
|
|||||||
|
|
||||||
_LIBCPP_BEGIN_NAMESPACE_STD
|
_LIBCPP_BEGIN_NAMESPACE_STD
|
||||||
|
|
||||||
|
// __lazy_and
|
||||||
|
|
||||||
|
template <bool _Last, class ..._Preds>
|
||||||
|
struct __lazy_and_impl;
|
||||||
|
|
||||||
|
template <class ..._Preds>
|
||||||
|
struct __lazy_and_impl<false, _Preds...> : false_type {};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct __lazy_and_impl<true> : true_type {};
|
||||||
|
|
||||||
|
template <class _Pred>
|
||||||
|
struct __lazy_and_impl<true, _Pred> : integral_constant<bool, _Pred::type::value> {};
|
||||||
|
|
||||||
|
template <class _Hp, class ..._Tp>
|
||||||
|
struct __lazy_and_impl<true, _Hp, _Tp...> : __lazy_and_impl<_Hp::type::value, _Tp...> {};
|
||||||
|
|
||||||
|
template <class _P1, class ..._Pr>
|
||||||
|
struct __lazy_and : __lazy_and_impl<_P1::type::value, _Pr...> {};
|
||||||
|
|
||||||
|
// __lazy_not
|
||||||
|
|
||||||
|
template <class _Pred>
|
||||||
|
struct __lazy_not : integral_constant<bool, !_Pred::type::value> {};
|
||||||
|
|
||||||
|
|
||||||
template <class _Tp> class _LIBCPP_TYPE_VIS_ONLY tuple_size;
|
template <class _Tp> class _LIBCPP_TYPE_VIS_ONLY tuple_size;
|
||||||
|
|
||||||
template <class _Tp>
|
template <class _Tp>
|
||||||
|
@@ -210,7 +210,13 @@ public:
|
|||||||
"Attempted to default construct a reference element in a tuple");}
|
"Attempted to default construct a reference element in a tuple");}
|
||||||
|
|
||||||
template <class _Tp,
|
template <class _Tp,
|
||||||
class = typename enable_if<is_constructible<_Hp, _Tp>::value>::type>
|
class = typename enable_if<
|
||||||
|
__lazy_and<
|
||||||
|
__lazy_not<is_same<typename decay<_Tp>::type, __tuple_leaf>>
|
||||||
|
, is_constructible<_Hp, _Tp>
|
||||||
|
>::value
|
||||||
|
>::type
|
||||||
|
>
|
||||||
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
|
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
|
||||||
explicit __tuple_leaf(_Tp&& __t) _NOEXCEPT_((is_nothrow_constructible<_Hp, _Tp>::value))
|
explicit __tuple_leaf(_Tp&& __t) _NOEXCEPT_((is_nothrow_constructible<_Hp, _Tp>::value))
|
||||||
: value(_VSTD::forward<_Tp>(__t))
|
: value(_VSTD::forward<_Tp>(__t))
|
||||||
@@ -316,7 +322,13 @@ public:
|
|||||||
: _Hp(__a) {}
|
: _Hp(__a) {}
|
||||||
|
|
||||||
template <class _Tp,
|
template <class _Tp,
|
||||||
class = typename enable_if<is_constructible<_Hp, _Tp>::value>::type>
|
class = typename enable_if<
|
||||||
|
__lazy_and<
|
||||||
|
__lazy_not<is_same<typename decay<_Tp>::type, __tuple_leaf>>
|
||||||
|
, is_constructible<_Hp, _Tp>
|
||||||
|
>::value
|
||||||
|
>::type
|
||||||
|
>
|
||||||
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
|
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
|
||||||
explicit __tuple_leaf(_Tp&& __t) _NOEXCEPT_((is_nothrow_constructible<_Hp, _Tp>::value))
|
explicit __tuple_leaf(_Tp&& __t) _NOEXCEPT_((is_nothrow_constructible<_Hp, _Tp>::value))
|
||||||
: _Hp(_VSTD::forward<_Tp>(__t)) {}
|
: _Hp(_VSTD::forward<_Tp>(__t)) {}
|
||||||
@@ -336,6 +348,9 @@ public:
|
|||||||
explicit __tuple_leaf(integral_constant<int, 2>, const _Alloc& __a, _Tp&& __t)
|
explicit __tuple_leaf(integral_constant<int, 2>, const _Alloc& __a, _Tp&& __t)
|
||||||
: _Hp(_VSTD::forward<_Tp>(__t), __a) {}
|
: _Hp(_VSTD::forward<_Tp>(__t), __a) {}
|
||||||
|
|
||||||
|
__tuple_leaf(__tuple_leaf const &) = default;
|
||||||
|
__tuple_leaf(__tuple_leaf &&) = default;
|
||||||
|
|
||||||
template <class _Tp>
|
template <class _Tp>
|
||||||
_LIBCPP_INLINE_VISIBILITY
|
_LIBCPP_INLINE_VISIBILITY
|
||||||
__tuple_leaf&
|
__tuple_leaf&
|
||||||
|
@@ -17,6 +17,40 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
|
|
||||||
|
template <class ...>
|
||||||
|
struct never {
|
||||||
|
enum { value = 0 };
|
||||||
|
};
|
||||||
|
|
||||||
|
struct NoValueCtor
|
||||||
|
{
|
||||||
|
NoValueCtor() : id(++count) {}
|
||||||
|
NoValueCtor(NoValueCtor const & other) : id(other.id) { ++count; }
|
||||||
|
|
||||||
|
// The constexpr is required to make is_constructible instantiate this template.
|
||||||
|
// The explicit is needed to test-around a similar bug with is_convertible.
|
||||||
|
template <class T>
|
||||||
|
constexpr explicit NoValueCtor(T)
|
||||||
|
{ static_assert(never<T>::value, "This should not be instantiated"); }
|
||||||
|
|
||||||
|
static int count;
|
||||||
|
int id;
|
||||||
|
};
|
||||||
|
|
||||||
|
int NoValueCtor::count = 0;
|
||||||
|
|
||||||
|
|
||||||
|
struct NoValueCtorEmpty
|
||||||
|
{
|
||||||
|
NoValueCtorEmpty() {}
|
||||||
|
NoValueCtorEmpty(NoValueCtorEmpty const &) {}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
constexpr explicit NoValueCtorEmpty(T)
|
||||||
|
{ static_assert(never<T>::value, "This should not be instantiated"); }
|
||||||
|
};
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
@@ -56,6 +90,23 @@ int main()
|
|||||||
assert(std::get<1>(t) == nullptr);
|
assert(std::get<1>(t) == nullptr);
|
||||||
assert(std::get<2>(t) == "text");
|
assert(std::get<2>(t) == "text");
|
||||||
}
|
}
|
||||||
|
// __tuple_leaf<T> uses is_constructible<T, U> to disable its explicit converting
|
||||||
|
// constructor overload __tuple_leaf(U &&). Evaluating is_constructible can cause a compile error.
|
||||||
|
// This overload is evaluated when __tuple_leafs copy or move ctor is called.
|
||||||
|
// This checks that is_constructible is not evaluated when U == __tuple_leaf.
|
||||||
|
{
|
||||||
|
std::tuple<int, NoValueCtor, int, int> t(1, NoValueCtor(), 2, 3);
|
||||||
|
assert(std::get<0>(t) == 1);
|
||||||
|
assert(std::get<1>(t).id == 1);
|
||||||
|
assert(std::get<2>(t) == 2);
|
||||||
|
assert(std::get<3>(t) == 3);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
std::tuple<int, NoValueCtorEmpty, int, int> t(1, NoValueCtorEmpty(), 2, 3);
|
||||||
|
assert(std::get<0>(t) == 1);
|
||||||
|
assert(std::get<2>(t) == 2);
|
||||||
|
assert(std::get<3>(t) == 3);
|
||||||
|
}
|
||||||
// extensions
|
// extensions
|
||||||
{
|
{
|
||||||
std::tuple<int, char*, std::string> t(2);
|
std::tuple<int, char*, std::string> t(2);
|
||||||
|
@@ -18,6 +18,18 @@
|
|||||||
|
|
||||||
#include "../MoveOnly.h"
|
#include "../MoveOnly.h"
|
||||||
|
|
||||||
|
struct ConstructsWithTupleLeaf
|
||||||
|
{
|
||||||
|
ConstructsWithTupleLeaf() {}
|
||||||
|
|
||||||
|
ConstructsWithTupleLeaf(ConstructsWithTupleLeaf const &) { assert(false); }
|
||||||
|
ConstructsWithTupleLeaf(ConstructsWithTupleLeaf &&) {}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
ConstructsWithTupleLeaf(T t)
|
||||||
|
{ assert(false); }
|
||||||
|
};
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
@@ -46,4 +58,12 @@ int main()
|
|||||||
assert(std::get<1>(t) == 1);
|
assert(std::get<1>(t) == 1);
|
||||||
assert(std::get<2>(t) == 2);
|
assert(std::get<2>(t) == 2);
|
||||||
}
|
}
|
||||||
|
// A bug in tuple caused __tuple_leaf to use its explicit converting constructor
|
||||||
|
// as its move constructor. This tests that ConstructsWithTupleLeaf is not called
|
||||||
|
// (w/ __tuple_leaf)
|
||||||
|
{
|
||||||
|
typedef std::tuple<ConstructsWithTupleLeaf> d_t;
|
||||||
|
d_t d((ConstructsWithTupleLeaf()));
|
||||||
|
d_t d2(static_cast<d_t &&>(d));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -18,7 +18,7 @@ int main()
|
|||||||
#if _LIBCPP_STD_VER > 11
|
#if _LIBCPP_STD_VER > 11
|
||||||
typedef std::complex<float> cf;
|
typedef std::complex<float> cf;
|
||||||
auto t1 = std::make_tuple<int, std::string> ( 42, "Hi" );
|
auto t1 = std::make_tuple<int, std::string> ( 42, "Hi" );
|
||||||
assert ( std::get<cf>(t1) == cf {1,2} ); // no such type
|
assert (( std::get<cf>(t1) == cf {1,2} )); // no such type
|
||||||
#else
|
#else
|
||||||
#error
|
#error
|
||||||
#endif
|
#endif
|
||||||
|
@@ -17,7 +17,7 @@ int main()
|
|||||||
#if _LIBCPP_STD_VER > 11
|
#if _LIBCPP_STD_VER > 11
|
||||||
typedef std::complex<float> cf;
|
typedef std::complex<float> cf;
|
||||||
auto t1 = std::make_pair<int, double> ( 42, 3.4 );
|
auto t1 = std::make_pair<int, double> ( 42, 3.4 );
|
||||||
assert ( std::get<cf>(t1) == cf {1,2} ); // no such type
|
assert (( std::get<cf>(t1) == cf {1,2} )); // no such type
|
||||||
#else
|
#else
|
||||||
#error
|
#error
|
||||||
#endif
|
#endif
|
||||||
|
Reference in New Issue
Block a user