diff mbox

libstdc++/72745 add static assertion for invalid tuple access

Message ID 20160731171004.GA12566@redhat.com
State New
Headers show

Commit Message

Jonathan Wakely July 31, 2016, 5:10 p.m. UTC
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 mbox

Patch

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" }
+}