diff options
author | Jonathan Wakely <jwakely@redhat.com> | 2018-08-17 18:52:49 +0100 |
---|---|---|
committer | Jonathan Wakely <redi@gcc.gnu.org> | 2018-08-17 18:52:49 +0100 |
commit | 478490f681da504e75723828d9f1b3b09928b5e5 (patch) | |
tree | 832430bb0a15d9fa69ca293fd004bf9c53bb98e8 /libstdc++-v3 | |
parent | 81bf52f56416c91706c32f651b411e4f4adfb413 (diff) | |
download | gcc-478490f681da504e75723828d9f1b3b09928b5e5.zip gcc-478490f681da504e75723828d9f1b3b09928b5e5.tar.gz gcc-478490f681da504e75723828d9f1b3b09928b5e5.tar.bz2 |
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
Diffstat (limited to 'libstdc++-v3')
-rw-r--r-- | libstdc++-v3/ChangeLog | 33 | ||||
-rw-r--r-- | libstdc++-v3/include/std/tuple | 125 | ||||
-rw-r--r-- | libstdc++-v3/python/libstdcxx/v6/printers.py | 23 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/20_util/tuple/dr2729.cc | 179 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/20_util/tuple/element_access/get_neg.cc | 2 |
5 files changed, 319 insertions, 43 deletions
diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 9477a33..95d4d06 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -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 diff --git a/libstdc++-v3/include/std/tuple b/libstdc++-v3/include/std/tuple index dd7daf7..955b853 100644 --- a/libstdc++-v3/include/std/tuple +++ b/libstdc++-v3/include/std/tuple @@ -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; diff --git a/libstdc++-v3/python/libstdcxx/v6/printers.py b/libstdc++-v3/python/libstdcxx/v6/printers.py index 43d459e..afe1b32 100644 --- a/libstdc++-v3/python/libstdcxx/v6/printers.py +++ b/libstdc++-v3/python/libstdcxx/v6/printers.py @@ -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): diff --git a/libstdc++-v3/testsuite/20_util/tuple/dr2729.cc b/libstdc++-v3/testsuite/20_util/tuple/dr2729.cc new file mode 100644 index 0000000..c386355 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/tuple/dr2729.cc @@ -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>&>(), "" ); diff --git a/libstdc++-v3/testsuite/20_util/tuple/element_access/get_neg.cc b/libstdc++-v3/testsuite/20_util/tuple/element_access/get_neg.cc index e76f53af..d550282 100644 --- a/libstdc++-v3/testsuite/20_util/tuple/element_access/get_neg.cc +++ b/libstdc++-v3/testsuite/20_util/tuple/element_access/get_neg.cc @@ -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> |