PR libstdc++/72745 * include/std/array (get): Use positive message for static assertions. * include/std/functional (_Safe_tuple_element_t): Fix indentation. * include/std/tuple (tuple_element<I, tuple<>>): Add partial specialization for invalid indices, with static assertion. * testsuite/20_util/tuple/element_access/get_neg.cc: New test.
This improves the diagnostic for std::get<1>( tuple<int>{} ) by adding a static assertion that the index is in range. Tested powerpc64-linux, committed to trunk.
commit 2fa24ef248c5df09960eaa872945ecbdc29f2a0b Author: redi <redi@138bc75d-0d04-0410-961f-82ee72b054a4> Date: Sun Jul 31 17:08:52 2016 +0000 libstdc++/72745 add static assertion for invalid tuple access PR libstdc++/72745 * include/std/array (get): Use positive message for static assertions. * include/std/functional (_Safe_tuple_element_t): Fix indentation. * include/std/tuple (tuple_element<I, tuple<>>): Add partial specialization for invalid indices, with static assertion. * testsuite/20_util/tuple/element_access/get_neg.cc: New test. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@238924 138bc75d-0d04-0410-961f-82ee72b054a4 diff --git a/libstdc++-v3/include/std/array b/libstdc++-v3/include/std/array index 73d2669..73a6fbc 100644 --- a/libstdc++-v3/include/std/array +++ b/libstdc++-v3/include/std/array @@ -292,7 +292,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER constexpr _Tp& get(array<_Tp, _Nm>& __arr) noexcept { - static_assert(_Int < _Nm, "index is out of bounds"); + static_assert(_Int < _Nm, "array index is within bounds"); return _GLIBCXX_STD_C::__array_traits<_Tp, _Nm>:: _S_ref(__arr._M_elems, _Int); } @@ -301,7 +301,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER constexpr _Tp&& get(array<_Tp, _Nm>&& __arr) noexcept { - static_assert(_Int < _Nm, "index is out of bounds"); + static_assert(_Int < _Nm, "array index is within bounds"); return std::move(_GLIBCXX_STD_C::get<_Int>(__arr)); } @@ -309,7 +309,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER constexpr const _Tp& get(const array<_Tp, _Nm>& __arr) noexcept { - static_assert(_Int < _Nm, "index is out of bounds"); + static_assert(_Int < _Nm, "array index is within bounds"); return _GLIBCXX_STD_C::__array_traits<_Tp, _Nm>:: _S_ref(__arr._M_elems, _Int); } diff --git a/libstdc++-v3/include/std/functional b/libstdc++-v3/include/std/functional index 97745ae..700505e 100644 --- a/libstdc++-v3/include/std/functional +++ b/libstdc++-v3/include/std/functional @@ -758,10 +758,10 @@ _GLIBCXX_MEM_FN_TRAITS(&&, false_type, true_type) // Like tuple_element_t but SFINAE-friendly. - template<std::size_t __i, typename _Tuple> - using _Safe_tuple_element_t - = typename enable_if<(__i < tuple_size<_Tuple>::value), - tuple_element<__i, _Tuple>>::type::type; + template<std::size_t __i, typename _Tuple> + using _Safe_tuple_element_t + = typename enable_if<(__i < tuple_size<_Tuple>::value), + tuple_element<__i, _Tuple>>::type::type; /** * Maps an argument to bind() into an actual argument to the bound diff --git a/libstdc++-v3/include/std/tuple b/libstdc++-v3/include/std/tuple index c1c924c..484cb48 100644 --- a/libstdc++-v3/include/std/tuple +++ b/libstdc++-v3/include/std/tuple @@ -1243,6 +1243,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION }; + /// class tuple_size + template<typename... _Elements> + struct tuple_size<tuple<_Elements...>> + : public integral_constant<std::size_t, sizeof...(_Elements)> { }; + +#if __cplusplus > 201402L + template <typename _Tp> + constexpr size_t tuple_size_v = tuple_size<_Tp>::value; +#endif + /** * Recursive case for tuple_element: strip off the first element in * the tuple and retrieve the (i-1)th element of the remaining tuple. @@ -1260,15 +1270,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION typedef _Head type; }; - /// class tuple_size - template<typename... _Elements> - struct tuple_size<tuple<_Elements...>> - : public integral_constant<std::size_t, sizeof...(_Elements)> { }; - -#if __cplusplus > 201402L - template <typename _Tp> - constexpr size_t tuple_size_v = tuple_size<_Tp>::value; -#endif + /** + * Error case for tuple_element: invalid index. + */ + template<size_t __i> + struct tuple_element<__i, tuple<>> + { + static_assert(__i < tuple_size<tuple<>>::value, + "tuple index is in range"); + }; template<std::size_t __i, typename _Head, typename... _Tail> constexpr _Head& 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 new file mode 100644 index 0000000..95ff697 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/tuple/element_access/get_neg.cc @@ -0,0 +1,61 @@ +// Copyright (C) 2016 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-options "-fno-show-column" } +// { dg-do compile { target c++14 } } +// { dg-error "in range" "" { target *-*-* } 1279 } + +#include <tuple> + +void +test01() +{ + using test_type = std::tuple<>; + test_type t; + std::get<0>(t); // { dg-error "no match" } + std::get<0>(const_cast<const test_type&>(t)); // { dg-error "no match" } + std::get<0>(static_cast<test_type&&>(t)); // { dg-error "no match" } + std::get<5>(t); // { dg-error "no match" } + std::get<5>(const_cast<const test_type&>(t)); // { dg-error "no match" } + std::get<5>(static_cast<test_type&&>(t)); // { dg-error "no match" } +} + +void +test02() +{ + using test_type = std::tuple<int>; + test_type t; + std::get<1>(t); // { dg-error "no match" } + std::get<1>(const_cast<const test_type&>(t)); // { dg-error "no match" } + std::get<1>(static_cast<test_type&&>(t)); // { dg-error "no match" } + std::get<5>(t); // { dg-error "no match" } + std::get<5>(const_cast<const test_type&>(t)); // { dg-error "no match" } + std::get<5>(static_cast<test_type&&>(t)); // { dg-error "no match" } +} + +void +test03() +{ + using test_type = std::tuple<int, int, int, int>; + test_type t; + std::get<5>(t); // { dg-error "no match" } + std::get<5>(const_cast<const test_type&>(t)); // { dg-error "no match" } + std::get<5>(static_cast<test_type&&>(t)); // { dg-error "no match" } + std::get<6>(t); // { dg-error "no match" } + std::get<6>(const_cast<const test_type&>(t)); // { dg-error "no match" } + std::get<6>(static_cast<test_type&&>(t)); // { dg-error "no match" } +}