PR libstdc++/86963 Implement LWG 2729 constraints on tuple assignment
PR libstdc++/86963 * include/std/tuple (__tuple_base): New class template with deleted copy assignment operator. (tuple, tuple<_T1, _T2>): Derive from __tuple_base<tuple> so that implicit copy/move assignment operator will be deleted/suppressed. (tuple::__assignable, tuple<_T1, _T2>::__assignable): New helper functions for SFINAE constraints on assignment operators. (tuple::__nothrow_assignable, tuple<_T1, _T2>::__nothrow_assignable): New helper functions for exception specifications. (tuple::operator=(const tuple&), tuple::operator=(tuple&&)) (tuple<_T1, _T2>::operator=(const tuple&)) (tuple<_T1, _T2>::operator=(tuple&&)): Change parameter types to __nonesuch_no_braces when the operator should be defined implicitly. Use __nothrow_assignable for exception specifications. (tuple::operator=(const tuple<_UElements...>&)) (tuple::operator=(tuple<_UElements...>&&)) (tuple<_T1, _T2>::operator=(const tuple<_U1, _U2>&)) (tuple<_T1, _T2>::operator=(tuple<_U1, _U2>&&)) (tuple<_T1, _T2>::operator=(const pair<_U1, _U2>&)) (tuple<_T1, _T2>::operator=(pair<_U1, _U2>&&)): Constrain using __assignable and use __nothrow_assignable for exception specifications. * python/libstdcxx/v6/printers.py (is_specialization_of): Accept gdb.Type as first argument, instead of a string. (StdTuplePrinter._iterator._is_nonempty_tuple): New method to check tuple for expected structure. (StdTuplePrinter._iterator.__init__): Use _is_nonempty_tuple. * testsuite/20_util/tuple/dr2729.cc: New test. * testsuite/20_util/tuple/element_access/get_neg.cc: Change dg-error to dg-prune-output. From-SVN: r263625
This commit is contained in:
parent
81bf52f564
commit
478490f681
5 changed files with 319 additions and 43 deletions
|
@ -1,3 +1,36 @@
|
|||
2018-08-17 Jonathan Wakely <jwakely@redhat.com>
|
||||
|
||||
PR libstdc++/86963
|
||||
* include/std/tuple (__tuple_base): New class template with deleted
|
||||
copy assignment operator.
|
||||
(tuple, tuple<_T1, _T2>): Derive from __tuple_base<tuple> so that
|
||||
implicit copy/move assignment operator will be deleted/suppressed.
|
||||
(tuple::__assignable, tuple<_T1, _T2>::__assignable): New helper
|
||||
functions for SFINAE constraints on assignment operators.
|
||||
(tuple::__nothrow_assignable, tuple<_T1, _T2>::__nothrow_assignable):
|
||||
New helper functions for exception specifications.
|
||||
(tuple::operator=(const tuple&), tuple::operator=(tuple&&))
|
||||
(tuple<_T1, _T2>::operator=(const tuple&))
|
||||
(tuple<_T1, _T2>::operator=(tuple&&)): Change parameter types to
|
||||
__nonesuch_no_braces when the operator should be defined implicitly.
|
||||
Use __nothrow_assignable for exception specifications.
|
||||
(tuple::operator=(const tuple<_UElements...>&))
|
||||
(tuple::operator=(tuple<_UElements...>&&))
|
||||
(tuple<_T1, _T2>::operator=(const tuple<_U1, _U2>&))
|
||||
(tuple<_T1, _T2>::operator=(tuple<_U1, _U2>&&))
|
||||
(tuple<_T1, _T2>::operator=(const pair<_U1, _U2>&))
|
||||
(tuple<_T1, _T2>::operator=(pair<_U1, _U2>&&)): Constrain using
|
||||
__assignable and use __nothrow_assignable for exception
|
||||
specifications.
|
||||
* python/libstdcxx/v6/printers.py (is_specialization_of): Accept
|
||||
gdb.Type as first argument, instead of a string.
|
||||
(StdTuplePrinter._iterator._is_nonempty_tuple): New method to check
|
||||
tuple for expected structure.
|
||||
(StdTuplePrinter._iterator.__init__): Use _is_nonempty_tuple.
|
||||
* testsuite/20_util/tuple/dr2729.cc: New test.
|
||||
* testsuite/20_util/tuple/element_access/get_neg.cc: Change dg-error
|
||||
to dg-prune-output.
|
||||
|
||||
2018-08-16 Jonathan Wakely <jwakely@redhat.com>
|
||||
|
||||
* include/tr1/legendre_function.tcc (__sph_legendre): Avoid warning
|
||||
|
|
|
@ -551,9 +551,23 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
}
|
||||
};
|
||||
|
||||
// The tag parameter ensures that in nested tuples each __tuple_base
|
||||
// is a different type and can use the empty base-class optimisation.
|
||||
template<typename _Tag>
|
||||
class __tuple_base
|
||||
{
|
||||
template<typename...> friend struct tuple;
|
||||
__tuple_base() = default;
|
||||
~__tuple_base() = default;
|
||||
__tuple_base(const __tuple_base&) = default;
|
||||
__tuple_base& operator=(const __tuple_base&) = delete;
|
||||
};
|
||||
|
||||
/// Primary class template, tuple
|
||||
template<typename... _Elements>
|
||||
class tuple : public _Tuple_impl<0, _Elements...>
|
||||
class tuple
|
||||
: public _Tuple_impl<0, _Elements...>,
|
||||
private __tuple_base<tuple<_Elements...>>
|
||||
{
|
||||
typedef _Tuple_impl<0, _Elements...> _Inherited;
|
||||
|
||||
|
@ -573,6 +587,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
}
|
||||
};
|
||||
|
||||
template<typename... _UElements>
|
||||
static constexpr
|
||||
__enable_if_t<sizeof...(_UElements) == sizeof...(_Elements), bool>
|
||||
__assignable()
|
||||
{ return __and_<is_assignable<_Elements&, _UElements>...>::value; }
|
||||
|
||||
template<typename... _UElements>
|
||||
static constexpr bool __nothrow_assignable()
|
||||
{
|
||||
return
|
||||
__and_<is_nothrow_assignable<_Elements&, _UElements>...>::value;
|
||||
}
|
||||
|
||||
public:
|
||||
template<typename _Dummy = void,
|
||||
typename enable_if<_TC2<_Dummy>::
|
||||
|
@ -832,36 +859,39 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
{ }
|
||||
|
||||
tuple&
|
||||
operator=(const tuple& __in)
|
||||
operator=(typename conditional<__assignable<const _Elements&...>(),
|
||||
const tuple&,
|
||||
const __nonesuch_no_braces&>::type __in)
|
||||
noexcept(__nothrow_assignable<const _Elements&...>())
|
||||
{
|
||||
static_cast<_Inherited&>(*this) = __in;
|
||||
return *this;
|
||||
}
|
||||
|
||||
tuple&
|
||||
operator=(tuple&& __in)
|
||||
noexcept(is_nothrow_move_assignable<_Inherited>::value)
|
||||
operator=(typename conditional<__assignable<_Elements...>(),
|
||||
tuple&&,
|
||||
__nonesuch_no_braces&&>::type __in)
|
||||
noexcept(__nothrow_assignable<_Elements...>())
|
||||
{
|
||||
static_cast<_Inherited&>(*this) = std::move(__in);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename... _UElements>
|
||||
typename
|
||||
enable_if<sizeof...(_UElements)
|
||||
== sizeof...(_Elements), tuple&>::type
|
||||
operator=(const tuple<_UElements...>& __in)
|
||||
{
|
||||
__enable_if_t<__assignable<const _UElements&...>(), tuple&>
|
||||
operator=(const tuple<_UElements...>& __in)
|
||||
noexcept(__nothrow_assignable<const _UElements&...>())
|
||||
{
|
||||
static_cast<_Inherited&>(*this) = __in;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename... _UElements>
|
||||
typename
|
||||
enable_if<sizeof...(_UElements)
|
||||
== sizeof...(_Elements), tuple&>::type
|
||||
operator=(tuple<_UElements...>&& __in)
|
||||
{
|
||||
__enable_if_t<__assignable<_UElements...>(), tuple&>
|
||||
operator=(tuple<_UElements...>&& __in)
|
||||
noexcept(__nothrow_assignable<_UElements...>())
|
||||
{
|
||||
static_cast<_Inherited&>(*this) = std::move(__in);
|
||||
return *this;
|
||||
}
|
||||
|
@ -904,10 +934,26 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
/// Partial specialization, 2-element tuple.
|
||||
/// Includes construction and assignment from a pair.
|
||||
template<typename _T1, typename _T2>
|
||||
class tuple<_T1, _T2> : public _Tuple_impl<0, _T1, _T2>
|
||||
class tuple<_T1, _T2>
|
||||
: public _Tuple_impl<0, _T1, _T2>,
|
||||
private __tuple_base<tuple<_T1, _T2>>
|
||||
{
|
||||
typedef _Tuple_impl<0, _T1, _T2> _Inherited;
|
||||
|
||||
template<typename _U1, typename _U2>
|
||||
static constexpr bool __assignable()
|
||||
{
|
||||
return __and_<is_assignable<_T1&, _U1>,
|
||||
is_assignable<_T2&, _U2>>::value;
|
||||
}
|
||||
|
||||
template<typename _U1, typename _U2>
|
||||
static constexpr bool __nothrow_assignable()
|
||||
{
|
||||
return __and_<is_nothrow_assignable<_T1&, _U1>,
|
||||
is_nothrow_assignable<_T2&, _U2>>::value;
|
||||
}
|
||||
|
||||
public:
|
||||
template <typename _U1 = _T1,
|
||||
typename _U2 = _T2,
|
||||
|
@ -915,9 +961,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
__is_implicitly_default_constructible<_U1>,
|
||||
__is_implicitly_default_constructible<_U2>>
|
||||
::value, bool>::type = true>
|
||||
|
||||
constexpr tuple()
|
||||
: _Inherited() { }
|
||||
constexpr tuple()
|
||||
: _Inherited() { }
|
||||
|
||||
template <typename _U1 = _T1,
|
||||
typename _U2 = _T2,
|
||||
|
@ -929,9 +974,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
__and_<__is_implicitly_default_constructible<_U1>,
|
||||
__is_implicitly_default_constructible<_U2>>>>
|
||||
::value, bool>::type = false>
|
||||
|
||||
explicit constexpr tuple()
|
||||
: _Inherited() { }
|
||||
explicit constexpr tuple()
|
||||
: _Inherited() { }
|
||||
|
||||
// Shortcut for the cases where constructors taking _T1, _T2
|
||||
// need to be constrained.
|
||||
|
@ -1206,49 +1250,58 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
std::forward<_U2>(__in.second)) { }
|
||||
|
||||
tuple&
|
||||
operator=(const tuple& __in)
|
||||
operator=(typename conditional<__assignable<const _T1&, const _T2&>(),
|
||||
const tuple&,
|
||||
const __nonesuch_no_braces&>::type __in)
|
||||
noexcept(__nothrow_assignable<const _T1&, const _T2&>())
|
||||
{
|
||||
static_cast<_Inherited&>(*this) = __in;
|
||||
return *this;
|
||||
}
|
||||
|
||||
tuple&
|
||||
operator=(tuple&& __in)
|
||||
noexcept(is_nothrow_move_assignable<_Inherited>::value)
|
||||
operator=(typename conditional<__assignable<_T1, _T2>(),
|
||||
tuple&&,
|
||||
__nonesuch_no_braces&&>::type __in)
|
||||
noexcept(__nothrow_assignable<_T1, _T2>())
|
||||
{
|
||||
static_cast<_Inherited&>(*this) = std::move(__in);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename _U1, typename _U2>
|
||||
tuple&
|
||||
operator=(const tuple<_U1, _U2>& __in)
|
||||
{
|
||||
__enable_if_t<__assignable<const _U1&, const _U2&>(), tuple&>
|
||||
operator=(const tuple<_U1, _U2>& __in)
|
||||
noexcept(__nothrow_assignable<const _U1&, const _U2&>())
|
||||
{
|
||||
static_cast<_Inherited&>(*this) = __in;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename _U1, typename _U2>
|
||||
tuple&
|
||||
operator=(tuple<_U1, _U2>&& __in)
|
||||
{
|
||||
__enable_if_t<__assignable<_U1, _U2>(), tuple&>
|
||||
operator=(tuple<_U1, _U2>&& __in)
|
||||
noexcept(__nothrow_assignable<_U1, _U2>())
|
||||
{
|
||||
static_cast<_Inherited&>(*this) = std::move(__in);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename _U1, typename _U2>
|
||||
tuple&
|
||||
operator=(const pair<_U1, _U2>& __in)
|
||||
{
|
||||
__enable_if_t<__assignable<const _U1&, const _U2&>(), tuple&>
|
||||
operator=(const pair<_U1, _U2>& __in)
|
||||
noexcept(__nothrow_assignable<const _U1&, const _U2&>())
|
||||
{
|
||||
this->_M_head(*this) = __in.first;
|
||||
this->_M_tail(*this)._M_head(*this) = __in.second;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename _U1, typename _U2>
|
||||
tuple&
|
||||
operator=(pair<_U1, _U2>&& __in)
|
||||
{
|
||||
__enable_if_t<__assignable<_U1, _U2>(), tuple&>
|
||||
operator=(pair<_U1, _U2>&& __in)
|
||||
noexcept(__nothrow_assignable<_U1, _U2>())
|
||||
{
|
||||
this->_M_head(*this) = std::forward<_U1>(__in.first);
|
||||
this->_M_tail(*this)._M_head(*this) = std::forward<_U2>(__in.second);
|
||||
return *this;
|
||||
|
|
|
@ -101,12 +101,14 @@ def find_type(orig, name):
|
|||
|
||||
_versioned_namespace = '__8::'
|
||||
|
||||
def is_specialization_of(type, template_name):
|
||||
def is_specialization_of(x, template_name):
|
||||
"Test if a type is a given template instantiation."
|
||||
global _versioned_namespace
|
||||
if type(x) is gdb.Type:
|
||||
x = x.tag
|
||||
if _versioned_namespace:
|
||||
return re.match('^std::(%s)?%s<.*>$' % (_versioned_namespace, template_name), type) is not None
|
||||
return re.match('^std::%s<.*>$' % template_name, type) is not None
|
||||
return re.match('^std::(%s)?%s<.*>$' % (_versioned_namespace, template_name), x) is not None
|
||||
return re.match('^std::%s<.*>$' % template_name, x) is not None
|
||||
|
||||
def strip_versioned_namespace(typename):
|
||||
global _versioned_namespace
|
||||
|
@ -413,17 +415,26 @@ class StdTuplePrinter:
|
|||
"Print a std::tuple"
|
||||
|
||||
class _iterator(Iterator):
|
||||
@staticmethod
|
||||
def _is_nonempty_tuple (nodes):
|
||||
if len (nodes) == 2:
|
||||
if is_specialization_of (nodes[1].type, '__tuple_base'):
|
||||
return True
|
||||
elif len (nodes) == 1:
|
||||
return True
|
||||
elif len (nodes) == 0:
|
||||
return False
|
||||
raise ValueError("Top of tuple tree does not consist of a single node.")
|
||||
|
||||
def __init__ (self, head):
|
||||
self.head = head
|
||||
|
||||
# Set the base class as the initial head of the
|
||||
# tuple.
|
||||
nodes = self.head.type.fields ()
|
||||
if len (nodes) == 1:
|
||||
if self._is_nonempty_tuple (nodes):
|
||||
# Set the actual head to the first pair.
|
||||
self.head = self.head.cast (nodes[0].type)
|
||||
elif len (nodes) != 0:
|
||||
raise ValueError("Top of tuple tree does not consist of a single node.")
|
||||
self.count = 0
|
||||
|
||||
def __iter__ (self):
|
||||
|
|
179
libstdc++-v3/testsuite/20_util/tuple/dr2729.cc
Normal file
179
libstdc++-v3/testsuite/20_util/tuple/dr2729.cc
Normal file
|
@ -0,0 +1,179 @@
|
|||
// Copyright (C) 2018 Free Software Foundation, Inc.
|
||||
//
|
||||
// This file is part of the GNU ISO C++ Library. This library is free
|
||||
// software; you can redistribute it and/or modify it under the
|
||||
// terms of the GNU General Public License as published by the
|
||||
// Free Software Foundation; either version 3, or (at your option)
|
||||
// any later version.
|
||||
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License along
|
||||
// with this library; see the file COPYING3. If not see
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
|
||||
// { dg-do compile { target c++11 } }
|
||||
|
||||
#include <tuple>
|
||||
#include <testsuite_tr1.h>
|
||||
|
||||
using std::tuple;
|
||||
using std::pair;
|
||||
using __gnu_test::assign::AnyAssign;
|
||||
using __gnu_test::assign::DelAnyAssign;
|
||||
using __gnu_test::assign::DelCopyAssign;
|
||||
using __gnu_test::CopyConsOnlyType;
|
||||
|
||||
// Copy assignment:
|
||||
template<typename T>
|
||||
constexpr bool copy() { return std::is_copy_assignable<T>::value; }
|
||||
|
||||
// Move assigmment:
|
||||
template<typename T>
|
||||
constexpr bool move() { return std::is_move_assignable<T>::value; }
|
||||
|
||||
static_assert( copy<tuple<>>(), "");
|
||||
static_assert( move<tuple<>>(), "");
|
||||
|
||||
static_assert( copy<tuple<int>>(), "");
|
||||
static_assert( copy<tuple<AnyAssign>>(), "");
|
||||
static_assert( copy<tuple<int, int>>(), "");
|
||||
static_assert( copy<tuple<AnyAssign, AnyAssign>>(), "");
|
||||
static_assert( copy<tuple<int, AnyAssign>>(), "");
|
||||
static_assert( copy<tuple<AnyAssign, int>>(), "");
|
||||
static_assert( copy<tuple<int, int, int>>(), "");
|
||||
static_assert( copy<tuple<AnyAssign, AnyAssign, AnyAssign>>(), "");
|
||||
static_assert( copy<tuple<int, AnyAssign, AnyAssign>>(), "");
|
||||
static_assert( copy<tuple<AnyAssign, int, AnyAssign>>(), "");
|
||||
static_assert( copy<tuple<AnyAssign, AnyAssign, int>>(), "");
|
||||
|
||||
static_assert( move<tuple<int>>(), "");
|
||||
static_assert( move<tuple<AnyAssign>>(), "");
|
||||
static_assert( move<tuple<int, int>>(), "");
|
||||
static_assert( move<tuple<AnyAssign, AnyAssign>>(), "");
|
||||
static_assert( move<tuple<int, AnyAssign>>(), "");
|
||||
static_assert( move<tuple<AnyAssign, int>>(), "");
|
||||
static_assert( move<tuple<int, int, int>>(), "");
|
||||
static_assert( move<tuple<AnyAssign, AnyAssign, AnyAssign>>(), "");
|
||||
static_assert( move<tuple<int, AnyAssign, AnyAssign>>(), "");
|
||||
static_assert( move<tuple<AnyAssign, int, AnyAssign>>(), "");
|
||||
static_assert( move<tuple<AnyAssign, AnyAssign, int>>(), "");
|
||||
|
||||
static_assert( ! copy<tuple<DelCopyAssign>>(), "");
|
||||
static_assert( ! copy<tuple<DelCopyAssign, int>>(), "");
|
||||
static_assert( ! copy<tuple<int, DelCopyAssign>>(), "");
|
||||
static_assert( ! copy<tuple<DelCopyAssign, int, int>>(), "");
|
||||
static_assert( ! copy<tuple<int, DelCopyAssign, int>>(), "");
|
||||
static_assert( ! copy<tuple<int, int, DelCopyAssign>>(), "");
|
||||
|
||||
static_assert( move<tuple<DelCopyAssign>>(), "");
|
||||
static_assert( move<tuple<DelCopyAssign, int>>(), "");
|
||||
static_assert( move<tuple<int, DelCopyAssign>>(), "");
|
||||
static_assert( move<tuple<DelCopyAssign, int, int>>(), "");
|
||||
static_assert( move<tuple<int, DelCopyAssign, int>>(), "");
|
||||
static_assert( move<tuple<int, int, DelCopyAssign>>(), "");
|
||||
|
||||
static_assert( ! move<tuple<CopyConsOnlyType>>(), "");
|
||||
static_assert( ! move<tuple<CopyConsOnlyType, int>>(), "");
|
||||
static_assert( ! move<tuple<int, CopyConsOnlyType>>(), "");
|
||||
static_assert( ! move<tuple<CopyConsOnlyType, int, int>>(), "");
|
||||
static_assert( ! move<tuple<int, CopyConsOnlyType, int>>(), "");
|
||||
static_assert( ! move<tuple<int, int, CopyConsOnlyType>>(), "");
|
||||
|
||||
// Assignment from different types of tuple (and pair):
|
||||
template<typename To, typename From>
|
||||
constexpr bool assign() { return std::is_assignable<To&, From>::value; }
|
||||
|
||||
// 0-tuples
|
||||
static_assert( ! assign<tuple<>, tuple<int>>(), "" );
|
||||
static_assert( ! assign<tuple<>, const tuple<int>&>(), "" );
|
||||
|
||||
// 1-tuples
|
||||
static_assert( ! assign<tuple<int>, tuple<>>(), "" );
|
||||
static_assert( ! assign<tuple<int>, const tuple<>&>(), "" );
|
||||
static_assert( ! assign<tuple<AnyAssign>, tuple<>>(), "" );
|
||||
static_assert( ! assign<tuple<AnyAssign>, tuple<int, int>>(), "" );
|
||||
static_assert( ! assign<tuple<AnyAssign>, pair<int, int>>(), "" );
|
||||
|
||||
static_assert( ! assign<tuple<void*>, tuple<int>>(), "" );
|
||||
static_assert( ! assign<tuple<void*>, const tuple<int>&>(), "" );
|
||||
|
||||
static_assert( assign<tuple<long>, tuple<int>>(), "" );
|
||||
static_assert( assign<tuple<long>, tuple<int>&>(), "" );
|
||||
static_assert( assign<tuple<long>, const tuple<int>>(), "" );
|
||||
static_assert( assign<tuple<long>, const tuple<int>&>(), "" );
|
||||
|
||||
// 2-tuples
|
||||
static_assert( assign<tuple<long, long>, tuple<int, int>>(), "" );
|
||||
static_assert( assign<tuple<long, long>, tuple<int, int>&>(), "" );
|
||||
static_assert( assign<tuple<long, long>, const tuple<int, int>>(), "" );
|
||||
static_assert( assign<tuple<long, long>, const tuple<int, int>&>(), "" );
|
||||
|
||||
static_assert( assign<tuple<long, long>, pair<int, int>>(), "" );
|
||||
static_assert( assign<tuple<long, long>, const pair<int, int>&>(), "" );
|
||||
static_assert( assign<tuple<long, long>, pair<int, int>>(), "" );
|
||||
static_assert( assign<tuple<long, long>, const pair<int, int>&&>(), "" );
|
||||
|
||||
static_assert( assign<tuple<DelCopyAssign, AnyAssign>,
|
||||
tuple<DelCopyAssign, int>>(), "" );
|
||||
static_assert( ! assign<tuple<DelCopyAssign, AnyAssign>,
|
||||
tuple<DelCopyAssign, int>&>(), "" );
|
||||
static_assert( ! assign<tuple<DelCopyAssign, AnyAssign>,
|
||||
const tuple<DelCopyAssign, int>&>(), "" );
|
||||
static_assert( ! assign<tuple<DelCopyAssign, AnyAssign>,
|
||||
const tuple<DelCopyAssign, int>&&>(), "" );
|
||||
|
||||
static_assert( assign<tuple<AnyAssign, DelCopyAssign>,
|
||||
tuple<int, DelCopyAssign>>(), "" );
|
||||
static_assert( ! assign<tuple<AnyAssign, DelCopyAssign>,
|
||||
tuple<int, DelCopyAssign>&>(), "" );
|
||||
static_assert( ! assign<tuple<AnyAssign, DelCopyAssign>,
|
||||
const tuple<int, DelCopyAssign>&>(), "" );
|
||||
static_assert( ! assign<tuple<AnyAssign, DelCopyAssign>,
|
||||
const tuple<int, DelCopyAssign>&&>(), "" );
|
||||
|
||||
static_assert( ! assign<tuple<void*, int>,
|
||||
tuple<int, int>>(), "" );
|
||||
static_assert( ! assign<tuple<void*, int>,
|
||||
const tuple<int, int>&>(), "" );
|
||||
|
||||
static_assert( assign<tuple<DelCopyAssign, AnyAssign>,
|
||||
pair<DelCopyAssign, int>>(), "" );
|
||||
static_assert( ! assign<tuple<DelCopyAssign, AnyAssign>,
|
||||
pair<DelCopyAssign, int>&>(), "" );
|
||||
static_assert( ! assign<tuple<DelCopyAssign, AnyAssign>,
|
||||
const pair<DelCopyAssign, int>&>(), "" );
|
||||
static_assert( ! assign<tuple<DelCopyAssign, AnyAssign>,
|
||||
const pair<DelCopyAssign, int>&&>(), "" );
|
||||
|
||||
static_assert( assign<tuple<AnyAssign, DelCopyAssign>,
|
||||
pair<int, DelCopyAssign>>(), "" );
|
||||
static_assert( ! assign<tuple<AnyAssign, DelCopyAssign>,
|
||||
pair<int, DelCopyAssign>&>(), "" );
|
||||
static_assert( ! assign<tuple<AnyAssign, DelCopyAssign>,
|
||||
const pair<int, DelCopyAssign>&>(), "" );
|
||||
static_assert( ! assign<tuple<AnyAssign, DelCopyAssign>,
|
||||
const pair<int, DelCopyAssign>&&>(), "" );
|
||||
|
||||
static_assert( ! assign<tuple<void*, int>,
|
||||
pair<int, int>>(), "" );
|
||||
static_assert( ! assign<tuple<void*, int>,
|
||||
const pair<int, int>&>(), "" );
|
||||
|
||||
// 3-tuples
|
||||
static_assert( assign<tuple<AnyAssign, DelCopyAssign, AnyAssign>,
|
||||
tuple<int, DelCopyAssign, int>>(), "" );
|
||||
static_assert( ! assign<tuple<AnyAssign, DelCopyAssign, AnyAssign>,
|
||||
tuple<int, DelCopyAssign, int>&>(), "" );
|
||||
static_assert( ! assign<tuple<AnyAssign, DelCopyAssign, AnyAssign>,
|
||||
const tuple<int, DelCopyAssign, int>&>(), "" );
|
||||
static_assert( ! assign<tuple<AnyAssign, DelCopyAssign, AnyAssign>,
|
||||
const tuple<int, DelCopyAssign, int>&&>(), "" );
|
||||
|
||||
static_assert( ! assign<tuple<int, void*, int>,
|
||||
tuple<int, int, int>>(), "" );
|
||||
static_assert( ! assign<tuple<int, void*, int>,
|
||||
const tuple<int, int, int>&>(), "" );
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
// { dg-options "-fno-show-column" }
|
||||
// { dg-do compile { target c++14 } }
|
||||
// { dg-error "in range" "" { target *-*-* } 1297 }
|
||||
// { dg-prune-output "tuple index is in range" }
|
||||
|
||||
#include <tuple>
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue