libstdc++: Improve diagnostics for std::get with invalid tuple index

This adds a deleted overload of std::get<I>(const tuple<Types...>&).
Invalid calls with an out of range index will match the deleted overload
and give a single, clear error about calling a deleted function, instead
of overload resolution errors for every std::get overload in the
library.

This changes the current output of 15+ errors (plus notes and associated
header context) into just two errors (plus context):

error: static assertion failed: tuple index must be in range
error: use of deleted function 'constexpr std::__enable_if_t<(__i >= sizeof... (_Types))> std::get(const std::tuple<_Types ...>&) [with long unsigned int __i = 1; _Elements = {int}; std::__enable_if_t<(__i >= sizeof... (_Types))> = void]'

This seems like a nice improvement, although PR c++/66968 means that
"_Types" is printed in the signature rather than "_Elements".

Signed-off-by: Jonathan Wakely <jwakely@redhat.com>

libstdc++-v3/ChangeLog:

	* include/std/tuple (get<I>): Add deleted overload for bad
	index.
	* testsuite/20_util/tuple/element_access/get_neg.cc: Adjust
	expected errors.
This commit is contained in:
Jonathan Wakely 2021-07-16 20:59:43 +01:00
parent a8b3861496
commit 3dbc7b809a
2 changed files with 26 additions and 22 deletions

View File

@ -1406,6 +1406,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
return std::forward<const __element_type>(std::__get_helper<__i>(__t));
}
/// @cond undocumented
// Deleted overload chosen for invalid indices.
template<size_t __i, typename... _Elements>
constexpr __enable_if_t<(__i >= sizeof...(_Elements))>
get(const tuple<_Elements...>&) = delete;
/// @endcond
#if __cplusplus >= 201402L
#define __cpp_lib_tuples_by_type 201304

View File

@ -25,12 +25,12 @@ 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" }
std::get<0>(t); // { dg-error "deleted" }
std::get<0>(const_cast<const test_type&>(t)); // { dg-error "deleted" }
std::get<0>(static_cast<test_type&&>(t)); // { dg-error "deleted" }
std::get<5>(t); // { dg-error "deleted" }
std::get<5>(const_cast<const test_type&>(t)); // { dg-error "deleted" }
std::get<5>(static_cast<test_type&&>(t)); // { dg-error "deleted" }
}
void
@ -38,12 +38,12 @@ 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" }
std::get<1>(t); // { dg-error "deleted" }
std::get<1>(const_cast<const test_type&>(t)); // { dg-error "deleted" }
std::get<1>(static_cast<test_type&&>(t)); // { dg-error "deleted" }
std::get<5>(t); // { dg-error "deleted" }
std::get<5>(const_cast<const test_type&>(t)); // { dg-error "deleted" }
std::get<5>(static_cast<test_type&&>(t)); // { dg-error "deleted" }
}
void
@ -51,15 +51,12 @@ 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" }
std::get<5>(t); // { dg-error "deleted" }
std::get<5>(const_cast<const test_type&>(t)); // { dg-error "deleted" }
std::get<5>(static_cast<test_type&&>(t)); // { dg-error "deleted" }
std::get<6>(t); // { dg-error "deleted" }
std::get<6>(const_cast<const test_type&>(t)); // { dg-error "deleted" }
std::get<6>(static_cast<test_type&&>(t)); // { dg-error "deleted" }
}
// { dg-prune-output "tuple index must be in range" }
// { dg-prune-output "no type named .type" }
// { dg-prune-output "type/value mismatch" }
// { dg-prune-output "use of deleted function" }
// { dg-error "tuple index must be in range" "" { target *-*-* } 0 }