aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonathan Wakely <jwakely@redhat.com>2024-10-22 16:06:12 +0100
committerJonathan Wakely <redi@gcc.gnu.org>2024-10-24 17:22:33 +0100
commit0dbc588acaa27a3a56bc9173bd577e1293f10046 (patch)
treea415cc21c565754dfe60e87df952909f9e8f8183
parentbf43fe6aa966eaf397ea3b8ebd6408d3d124e285 (diff)
downloadgcc-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/variant32
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))...);