Commit c43c3af2 by Jonathan Wakely Committed by Jonathan Wakely

PR libstdc++/90246 Improve text of std::variant exceptions and assertions

	PR libstdc++/90246
	* include/std/variant (holds_alternative, get, get_if): Improve
	static assertion messages.
	(bad_variant_access::bad_variant_access()): Change default message.
	(__throw_bad_variant_access(bool)): New overload.
	(get): Use new overload.
	(visit, visit<R>): Improve exception message.

From-SVN: r271326
parent ac781bc8
2019-05-17 Jonathan Wakely <jwakely@redhat.com> 2019-05-17 Jonathan Wakely <jwakely@redhat.com>
PR libstdc++/90246
* include/std/variant (holds_alternative, get, get_if): Improve
static assertion messages.
(bad_variant_access::bad_variant_access()): Change default message.
(__throw_bad_variant_access(bool)): New overload.
(get): Use new overload.
(visit, visit<R>): Improve exception message.
* testsuite/20_util/variant/compile.cc: Fix narrowing test for ILP32 * testsuite/20_util/variant/compile.cc: Fix narrowing test for ILP32
targets. Add more cases from P0608R3. targets. Add more cases from P0608R3.
* testsuite/20_util/variant/run.cc: Add more cases from P0608R3. * testsuite/20_util/variant/run.cc: Add more cases from P0608R3.
......
...@@ -1065,7 +1065,7 @@ namespace __variant ...@@ -1065,7 +1065,7 @@ namespace __variant
holds_alternative(const variant<_Types...>& __v) noexcept holds_alternative(const variant<_Types...>& __v) noexcept
{ {
static_assert(__detail::__variant::__exactly_once<_Tp, _Types...>, static_assert(__detail::__variant::__exactly_once<_Tp, _Types...>,
"T should occur for exactly once in alternatives"); "T must occur exactly once in alternatives");
return __v.index() == __detail::__variant::__index_of_v<_Tp, _Types...>; return __v.index() == __detail::__variant::__index_of_v<_Tp, _Types...>;
} }
...@@ -1073,7 +1073,7 @@ namespace __variant ...@@ -1073,7 +1073,7 @@ namespace __variant
constexpr _Tp& get(variant<_Types...>& __v) constexpr _Tp& get(variant<_Types...>& __v)
{ {
static_assert(__detail::__variant::__exactly_once<_Tp, _Types...>, static_assert(__detail::__variant::__exactly_once<_Tp, _Types...>,
"T should occur for exactly once in alternatives"); "T must occur exactly once in alternatives");
static_assert(!is_void_v<_Tp>, "_Tp should not be void"); static_assert(!is_void_v<_Tp>, "_Tp should not be void");
return std::get<__detail::__variant::__index_of_v<_Tp, _Types...>>(__v); return std::get<__detail::__variant::__index_of_v<_Tp, _Types...>>(__v);
} }
...@@ -1082,7 +1082,7 @@ namespace __variant ...@@ -1082,7 +1082,7 @@ namespace __variant
constexpr _Tp&& get(variant<_Types...>&& __v) constexpr _Tp&& get(variant<_Types...>&& __v)
{ {
static_assert(__detail::__variant::__exactly_once<_Tp, _Types...>, static_assert(__detail::__variant::__exactly_once<_Tp, _Types...>,
"T should occur for exactly once in alternatives"); "T must occur exactly once in alternatives");
static_assert(!is_void_v<_Tp>, "_Tp should not be void"); static_assert(!is_void_v<_Tp>, "_Tp should not be void");
return std::get<__detail::__variant::__index_of_v<_Tp, _Types...>>( return std::get<__detail::__variant::__index_of_v<_Tp, _Types...>>(
std::move(__v)); std::move(__v));
...@@ -1092,7 +1092,7 @@ namespace __variant ...@@ -1092,7 +1092,7 @@ namespace __variant
constexpr const _Tp& get(const variant<_Types...>& __v) constexpr const _Tp& get(const variant<_Types...>& __v)
{ {
static_assert(__detail::__variant::__exactly_once<_Tp, _Types...>, static_assert(__detail::__variant::__exactly_once<_Tp, _Types...>,
"T should occur for exactly once in alternatives"); "T must occur exactly once in alternatives");
static_assert(!is_void_v<_Tp>, "_Tp should not be void"); static_assert(!is_void_v<_Tp>, "_Tp should not be void");
return std::get<__detail::__variant::__index_of_v<_Tp, _Types...>>(__v); return std::get<__detail::__variant::__index_of_v<_Tp, _Types...>>(__v);
} }
...@@ -1101,7 +1101,7 @@ namespace __variant ...@@ -1101,7 +1101,7 @@ namespace __variant
constexpr const _Tp&& get(const variant<_Types...>&& __v) constexpr const _Tp&& get(const variant<_Types...>&& __v)
{ {
static_assert(__detail::__variant::__exactly_once<_Tp, _Types...>, static_assert(__detail::__variant::__exactly_once<_Tp, _Types...>,
"T should occur for exactly once in alternatives"); "T must occur exactly once in alternatives");
static_assert(!is_void_v<_Tp>, "_Tp should not be void"); static_assert(!is_void_v<_Tp>, "_Tp should not be void");
return std::get<__detail::__variant::__index_of_v<_Tp, _Types...>>( return std::get<__detail::__variant::__index_of_v<_Tp, _Types...>>(
std::move(__v)); std::move(__v));
...@@ -1139,7 +1139,7 @@ namespace __variant ...@@ -1139,7 +1139,7 @@ namespace __variant
get_if(variant<_Types...>* __ptr) noexcept get_if(variant<_Types...>* __ptr) noexcept
{ {
static_assert(__detail::__variant::__exactly_once<_Tp, _Types...>, static_assert(__detail::__variant::__exactly_once<_Tp, _Types...>,
"T should occur for exactly once in alternatives"); "T must occur exactly once in alternatives");
static_assert(!is_void_v<_Tp>, "_Tp should not be void"); static_assert(!is_void_v<_Tp>, "_Tp should not be void");
return std::get_if<__detail::__variant::__index_of_v<_Tp, _Types...>>( return std::get_if<__detail::__variant::__index_of_v<_Tp, _Types...>>(
__ptr); __ptr);
...@@ -1150,7 +1150,7 @@ namespace __variant ...@@ -1150,7 +1150,7 @@ namespace __variant
get_if(const variant<_Types...>* __ptr) noexcept get_if(const variant<_Types...>* __ptr) noexcept
{ {
static_assert(__detail::__variant::__exactly_once<_Tp, _Types...>, static_assert(__detail::__variant::__exactly_once<_Tp, _Types...>,
"T should occur for exactly once in alternatives"); "T must occur exactly once in alternatives");
static_assert(!is_void_v<_Tp>, "_Tp should not be void"); static_assert(!is_void_v<_Tp>, "_Tp should not be void");
return std::get_if<__detail::__variant::__index_of_v<_Tp, _Types...>>( return std::get_if<__detail::__variant::__index_of_v<_Tp, _Types...>>(
__ptr); __ptr);
...@@ -1213,22 +1213,34 @@ namespace __variant ...@@ -1213,22 +1213,34 @@ namespace __variant
class bad_variant_access : public exception class bad_variant_access : public exception
{ {
public: public:
bad_variant_access() noexcept : _M_reason("Unknown reason") { } bad_variant_access() noexcept { }
const char* what() const noexcept override const char* what() const noexcept override
{ return _M_reason; } { return _M_reason; }
private: private:
bad_variant_access(const char* __reason) : _M_reason(__reason) { } bad_variant_access(const char* __reason) noexcept : _M_reason(__reason) { }
const char* _M_reason; // Must point to a string with static storage duration:
const char* _M_reason = "bad variant access";
friend void __throw_bad_variant_access(const char* __what); friend void __throw_bad_variant_access(const char* __what);
}; };
// Must only be called with a string literal
inline void inline void
__throw_bad_variant_access(const char* __what) __throw_bad_variant_access(const char* __what)
{ _GLIBCXX_THROW_OR_ABORT(bad_variant_access(__what)); } { _GLIBCXX_THROW_OR_ABORT(bad_variant_access(__what)); }
inline void
__throw_bad_variant_access(bool __valueless)
{
if (__valueless) [[__unlikely__]]
__throw_bad_variant_access("std::get: variant is valueless");
else
__throw_bad_variant_access("std::get: wrong index for variant");
}
template<typename... _Types> template<typename... _Types>
class variant class variant
: private __detail::__variant::_Variant_base<_Types...>, : private __detail::__variant::_Variant_base<_Types...>,
...@@ -1592,7 +1604,7 @@ namespace __variant ...@@ -1592,7 +1604,7 @@ namespace __variant
static_assert(_Np < sizeof...(_Types), static_assert(_Np < sizeof...(_Types),
"The index should be in [0, number of alternatives)"); "The index should be in [0, number of alternatives)");
if (__v.index() != _Np) if (__v.index() != _Np)
__throw_bad_variant_access("Unexpected index"); __throw_bad_variant_access(__v.valueless_by_exception());
return __detail::__variant::__get<_Np>(__v); return __detail::__variant::__get<_Np>(__v);
} }
...@@ -1603,7 +1615,7 @@ namespace __variant ...@@ -1603,7 +1615,7 @@ namespace __variant
static_assert(_Np < sizeof...(_Types), static_assert(_Np < sizeof...(_Types),
"The index should be in [0, number of alternatives)"); "The index should be in [0, number of alternatives)");
if (__v.index() != _Np) if (__v.index() != _Np)
__throw_bad_variant_access("Unexpected index"); __throw_bad_variant_access(__v.valueless_by_exception());
return __detail::__variant::__get<_Np>(std::move(__v)); return __detail::__variant::__get<_Np>(std::move(__v));
} }
...@@ -1614,7 +1626,7 @@ namespace __variant ...@@ -1614,7 +1626,7 @@ namespace __variant
static_assert(_Np < sizeof...(_Types), static_assert(_Np < sizeof...(_Types),
"The index should be in [0, number of alternatives)"); "The index should be in [0, number of alternatives)");
if (__v.index() != _Np) if (__v.index() != _Np)
__throw_bad_variant_access("Unexpected index"); __throw_bad_variant_access(__v.valueless_by_exception());
return __detail::__variant::__get<_Np>(__v); return __detail::__variant::__get<_Np>(__v);
} }
...@@ -1625,7 +1637,7 @@ namespace __variant ...@@ -1625,7 +1637,7 @@ namespace __variant
static_assert(_Np < sizeof...(_Types), static_assert(_Np < sizeof...(_Types),
"The index should be in [0, number of alternatives)"); "The index should be in [0, number of alternatives)");
if (__v.index() != _Np) if (__v.index() != _Np)
__throw_bad_variant_access("Unexpected index"); __throw_bad_variant_access(__v.valueless_by_exception());
return __detail::__variant::__get<_Np>(std::move(__v)); return __detail::__variant::__get<_Np>(std::move(__v));
} }
...@@ -1646,7 +1658,7 @@ namespace __variant ...@@ -1646,7 +1658,7 @@ namespace __variant
visit(_Visitor&& __visitor, _Variants&&... __variants) visit(_Visitor&& __visitor, _Variants&&... __variants)
{ {
if ((__variants.valueless_by_exception() || ...)) if ((__variants.valueless_by_exception() || ...))
__throw_bad_variant_access("Unexpected index"); __throw_bad_variant_access("std::visit: variant is valueless");
using _Result_type = std::invoke_result_t<_Visitor, using _Result_type = std::invoke_result_t<_Visitor,
decltype(std::get<0>(std::declval<_Variants>()))...>; decltype(std::get<0>(std::declval<_Variants>()))...>;
...@@ -1663,7 +1675,7 @@ namespace __variant ...@@ -1663,7 +1675,7 @@ namespace __variant
visit(_Visitor&& __visitor, _Variants&&... __variants) visit(_Visitor&& __visitor, _Variants&&... __variants)
{ {
if ((__variants.valueless_by_exception() || ...)) if ((__variants.valueless_by_exception() || ...))
__throw_bad_variant_access("Unexpected index"); __throw_bad_variant_access("std::visit<R>: variant is valueless");
return std::__do_visit<_Res>(std::forward<_Visitor>(__visitor), return std::__do_visit<_Res>(std::forward<_Visitor>(__visitor),
std::forward<_Variants>(__variants)...); std::forward<_Variants>(__variants)...);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment