From 4d895214e6b534643f7055b456efcb5fee3b228c Mon Sep 17 00:00:00 2001 From: Jonathan Wakely Date: Sun, 31 Jul 2016 17:08:52 +0000 Subject: 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>): Add partial specialization for invalid indices, with static assertion. * testsuite/20_util/tuple/element_access/get_neg.cc: New test. git-svn-id: https://gcc.gnu.org/svn/gcc/trunk@238924 138bc75d-0d04-0410-961f-82ee72b054a4 --- libstdc++-v3/ChangeLog | 7 +++ libstdc++-v3/include/std/array | 6 +-- libstdc++-v3/include/std/functional | 8 +-- libstdc++-v3/include/std/tuple | 28 ++++++---- .../20_util/tuple/element_access/get_neg.cc | 61 ++++++++++++++++++++++ 5 files changed, 94 insertions(+), 16 deletions(-) create mode 100644 libstdc++-v3/testsuite/20_util/tuple/element_access/get_neg.cc diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index a50066eef11..b79a4053afd 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,5 +1,12 @@ 2016-07-31 Jonathan Wakely + 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>): Add partial + specialization for invalid indices, with static assertion. + * testsuite/20_util/tuple/element_access/get_neg.cc: New test. + * testsuite/20_util/duration/requirements/typedefs_neg3.cc: Move dg-error to relevant line. * testsuite/20_util/headers/type_traits/types_std_c++0x_neg.cc: diff --git a/libstdc++-v3/include/std/array b/libstdc++-v3/include/std/array index 73d26698f72..73a6fbce4f3 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 97745aeb33b..700505e8f24 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 - using _Safe_tuple_element_t - = typename enable_if<(__i < tuple_size<_Tuple>::value), - tuple_element<__i, _Tuple>>::type::type; + template + 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 c1c924c1212..484cb4822f2 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 + struct tuple_size> + : public integral_constant { }; + +#if __cplusplus > 201402L + template + 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 - struct tuple_size> - : public integral_constant { }; - -#if __cplusplus > 201402L - template - constexpr size_t tuple_size_v = tuple_size<_Tp>::value; -#endif + /** + * Error case for tuple_element: invalid index. + */ + template + struct tuple_element<__i, tuple<>> + { + static_assert(__i < tuple_size>::value, + "tuple index is in range"); + }; template 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 00000000000..95ff697ae7a --- /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 +// . + +// { dg-options "-fno-show-column" } +// { dg-do compile { target c++14 } } +// { dg-error "in range" "" { target *-*-* } 1279 } + +#include + +void +test01() +{ + using test_type = std::tuple<>; + test_type t; + std::get<0>(t); // { dg-error "no match" } + std::get<0>(const_cast(t)); // { dg-error "no match" } + std::get<0>(static_cast(t)); // { dg-error "no match" } + std::get<5>(t); // { dg-error "no match" } + std::get<5>(const_cast(t)); // { dg-error "no match" } + std::get<5>(static_cast(t)); // { dg-error "no match" } +} + +void +test02() +{ + using test_type = std::tuple; + test_type t; + std::get<1>(t); // { dg-error "no match" } + std::get<1>(const_cast(t)); // { dg-error "no match" } + std::get<1>(static_cast(t)); // { dg-error "no match" } + std::get<5>(t); // { dg-error "no match" } + std::get<5>(const_cast(t)); // { dg-error "no match" } + std::get<5>(static_cast(t)); // { dg-error "no match" } +} + +void +test03() +{ + using test_type = std::tuple; + test_type t; + std::get<5>(t); // { dg-error "no match" } + std::get<5>(const_cast(t)); // { dg-error "no match" } + std::get<5>(static_cast(t)); // { dg-error "no match" } + std::get<6>(t); // { dg-error "no match" } + std::get<6>(const_cast(t)); // { dg-error "no match" } + std::get<6>(static_cast(t)); // { dg-error "no match" } +} -- cgit v1.2.3