This removes the overload of __throw_bad_variant_access that must be
called with a string literal. This avoids a potential source of
undefined behaviour if that function got misused. The other overload
that takes a bool parameter can be adjusted to take an int describing
which of the four possible string literals to use, and ensure that the
std::bad_variant_access constructor is only called with those. Passing
an int outside the range [0,3] is bogus, but will still select a valid
string literal and avoid undefined behaviour.
libstdc++-v3/ChangeLog:
* include/std/variant (bad_variant_access): Adjust friend
declaration.
(__throw_bad_variant_access(const char*)): Remove.
(__throw_bad_variant_access(bool)): Change parameter to int.
(visit, visit<R>): Adjust calls to __throw_bad_variant_access.
---
Tested x86_64-linux.
Also available for review at https://forge.sourceware.org/gcc/gcc-TEST/pulls/3
libstdc++-v3/include/std/variant | 25 ++++++++++++-------------
1 file changed, 12 insertions(+), 13 deletions(-)
diff --git a/libstdc++-v3/include/std/variant b/libstdc++-v3/include/std/variant
index cf532126d79..d79299be634 100644
--- a/libstdc++-v3/include/std/variant
+++ b/libstdc++-v3/include/std/variant
@@ -1411,26 +1411,25 @@ namespace __detail::__variant
{ return _M_reason; }
private:
+ // Must only be called with a string literal
bad_variant_access(const char* __reason) noexcept : _M_reason(__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(int);
};
- // Must only be called with a string literal
inline void
- __throw_bad_variant_access(const char* __what)
- { _GLIBCXX_THROW_OR_ABORT(bad_variant_access(__what)); }
-
- inline void
- __throw_bad_variant_access(bool __valueless)
+ __throw_bad_variant_access(int __reason)
{
- if (__valueless) [[__unlikely__]]
- __throw_bad_variant_access("std::get: variant is valueless");
- else
- __throw_bad_variant_access("std::get: wrong index for variant");
+ const char* __reasons[] = {
+ "std::get: wrong index for variant",
+ "std::get: variant is valueless",
+ "std::visit: variant is valueless",
+ "std::visit<R>: variant is valueless"
+ };
+ _GLIBCXX_THROW_OR_ABORT(bad_variant_access(__reasons[__reason % 4u]));
}
template<typename... _Types>
@@ -1941,7 +1940,7 @@ namespace __detail::__variant
namespace __variant = std::__detail::__variant;
if ((__variant::__as(__variants).valueless_by_exception() || ...))
- __throw_bad_variant_access("std::visit: variant is valueless");
+ __throw_bad_variant_access(2);
using _Result_type
= __detail::__variant::__visit_result_t<_Visitor, _Variants...>;
@@ -1981,7 +1980,7 @@ namespace __detail::__variant
namespace __variant = std::__detail::__variant;
if ((__variant::__as(__variants).valueless_by_exception() || ...))
- __throw_bad_variant_access("std::visit<R>: variant is valueless");
+ __throw_bad_variant_access(3);
return std::__do_visit<_Res>(std::forward<_Visitor>(__visitor),
__variant::__as(std::forward<_Variants>(__variants))...);
--
2.46.2