diff options
author | Jonathan Wakely <jwakely@redhat.com> | 2024-10-22 16:06:12 +0100 |
---|---|---|
committer | Jonathan Wakely <redi@gcc.gnu.org> | 2024-10-24 17:22:33 +0100 |
commit | 0dbc588acaa27a3a56bc9173bd577e1293f10046 (patch) | |
tree | a415cc21c565754dfe60e87df952909f9e8f8183 | |
parent | bf43fe6aa966eaf397ea3b8ebd6408d3d124e285 (diff) | |
download | gcc-0dbc588acaa27a3a56bc9173bd577e1293f10046.zip gcc-0dbc588acaa27a3a56bc9173bd577e1293f10046.tar.gz gcc-0dbc588acaa27a3a56bc9173bd577e1293f10046.tar.bz2 |
libstdc++: Simplify std::__throw_bad_variant_access
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 integer index
selecting one of the four possible string literals to use, ensuring
that the std::bad_variant_access constructor is only called with those
literals.
Passing an index 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 (__throw_bad_variant_access(unsigned)):
Define new function as inline friend, with namespace-scope
declaration using noreturn attribute.
(__throw_bad_variant_access(const char*)): Remove.
(__throw_bad_variant_access(bool)): Remove.
(visit, visit<R>): Adjust calls to __throw_bad_variant_access.
Reviewed-by: Patrick Palka <ppalka@redhat.com>
-rw-r--r-- | libstdc++-v3/include/std/variant | 32 |
1 files changed, 15 insertions, 17 deletions
diff --git a/libstdc++-v3/include/std/variant b/libstdc++-v3/include/std/variant index cf53212..bd0f9c3 100644 --- a/libstdc++-v3/include/std/variant +++ b/libstdc++-v3/include/std/variant @@ -1402,6 +1402,8 @@ namespace __detail::__variant && (is_swappable_v<_Types> && ...))> swap(variant<_Types...>&, variant<_Types...>&) = delete; + [[noreturn]] void __throw_bad_variant_access(unsigned); + class bad_variant_access : public exception { public: @@ -1411,28 +1413,24 @@ 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([[maybe_unused]] unsigned __n) + { + [[maybe_unused]] static constexpr 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[__n % 4u])); + } }; - // 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) - { - 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> class variant : private __detail::__variant::_Variant_base<_Types...>, @@ -1941,7 +1939,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 +1979,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))...); |