libstdc++/72745 add static assertion for invalid tuple access
authorJonathan Wakely <jwakely@redhat.com>
Sun, 31 Jul 2016 17:08:52 +0000 (18:08 +0100)
committerJonathan Wakely <redi@gcc.gnu.org>
Sun, 31 Jul 2016 17:08:52 +0000 (18:08 +0100)
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.

From-SVN: r238924

libstdc++-v3/ChangeLog
libstdc++-v3/include/std/array
libstdc++-v3/include/std/functional
libstdc++-v3/include/std/tuple
libstdc++-v3/testsuite/20_util/tuple/element_access/get_neg.cc [new file with mode: 0644]

index a50066eef111ace32a1d3f7f6698e62946462b67..b79a4053afd585410627b4e8adfed4b8c127a85b 100644 (file)
@@ -1,5 +1,12 @@
 2016-07-31  Jonathan Wakely  <jwakely@redhat.com>
 
+       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.
+
        * 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:
index 73d26698f72010d664eaa405a5bdb87df47fe8ec..73a6fbce4f32362c9ad838a75deb47f968d8875b 100644 (file)
@@ -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);
     }
index 97745aeb33bd3ad3d93a81cc78337588b6ba920b..700505e8f249d4b34e7ab542384be73f555d9e4d 100644 (file)
@@ -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
index c1c924c12122cb38dc94a77e960f2d03af075598..484cb4822f24a727ab7e00c66905035fb607a50b 100644 (file)
@@ -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 (file)
index 0000000..95ff697
--- /dev/null
@@ -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" }
+}