[libcxx-commits] [libcxx] [libcxx] Enrich message for std::bad_variant_access exception (PR #196495)
Nikita Grivin via libcxx-commits
libcxx-commits at lists.llvm.org
Sun May 10 12:11:13 PDT 2026
https://github.com/MindSpectre updated https://github.com/llvm/llvm-project/pull/196495
>From da1a28f2e3dea5fde634ef16cda66573cbe3ac4b Mon Sep 17 00:00:00 2001
From: Polaris <neuronspectrelin at gmail.com>
Date: Fri, 8 May 2026 01:24:05 +0300
Subject: [PATCH] [libc++] Improve messages for std::bad_variant_access
exception
std::bad_variant_access::what() now returns a more descriptive message identifying the failing operation (e.g., std::get: variant is valueless) instead of the generic bad_variant_access
---
libcxx/docs/ReleaseNotes/23.rst | 4 +
libcxx/include/__configuration/availability.h | 14 +++
libcxx/include/variant | 27 +++++-
...bcxxabi.v1.stable.exceptions.nonew.abilist | 4 +
...bcxxabi.v1.stable.exceptions.nonew.abilist | 4 +
...bcxxabi.v1.stable.exceptions.nonew.abilist | 4 +
...bcxxabi.v1.stable.exceptions.nonew.abilist | 4 +
...bcxxabi.v1.stable.exceptions.nonew.abilist | 4 +
...bcxxabi.v1.stable.exceptions.nonew.abilist | 4 +
...bcxxabi.v1.stable.exceptions.nonew.abilist | 4 +
...bcxxabi.v1.stable.exceptions.nonew.abilist | 4 +
libcxx/src/variant.cpp | 4 +
.../good_what_message.pass.cpp | 92 +++++++++++++++++++
13 files changed, 169 insertions(+), 4 deletions(-)
create mode 100644 libcxx/test/libcxx/utilities/variant/variant.bad_variant_access/good_what_message.pass.cpp
diff --git a/libcxx/docs/ReleaseNotes/23.rst b/libcxx/docs/ReleaseNotes/23.rst
index a34e379b145fe..4ec0f5febeac0 100644
--- a/libcxx/docs/ReleaseNotes/23.rst
+++ b/libcxx/docs/ReleaseNotes/23.rst
@@ -58,6 +58,10 @@ Improvements and New Features
for ``std::deque<int>`` iterators.
- ``std::copy(CharT*, CharT*, ostreambuf_iterator<CharT>)`` has been optimized, resulting in performance improvements
of up to 25x.
+- ``std::bad_variant_access::what()`` now returns a message identifying the cause of the failure:
+ ``"std::visit: variant is valueless"``, ``"std::get: variant is valueless"``, or
+ ``"std::get: wrong alternative for variant"``. The standard only requires ``what()`` to return an
+ unspecified non-null string, so user code that does not match on the exact message remains correct.
Deprecations and Removals
-------------------------
diff --git a/libcxx/include/__configuration/availability.h b/libcxx/include/__configuration/availability.h
index f1a598b5206f4..7420004489a97 100644
--- a/libcxx/include/__configuration/availability.h
+++ b/libcxx/include/__configuration/availability.h
@@ -39,6 +39,9 @@
// in all versions of the library are available.
#if !_LIBCPP_HAS_VENDOR_AVAILABILITY_ANNOTATIONS
+# define _LIBCPP_INTRODUCED_IN_LLVM_23 1
+# define _LIBCPP_INTRODUCED_IN_LLVM_23_ATTRIBUTE /* nothing */
+
# define _LIBCPP_INTRODUCED_IN_LLVM_22 1
# define _LIBCPP_INTRODUCED_IN_LLVM_22_ATTRIBUTE /* nothing */
@@ -70,6 +73,11 @@
// clang-format off
+// LLVM 23
+// TODO: Fill this in
+# define _LIBCPP_INTRODUCED_IN_LLVM_23 0
+# define _LIBCPP_INTRODUCED_IN_LLVM_23_ATTRIBUTE __attribute__((unavailable))
+
// LLVM 22
// TODO: Fill this in
# define _LIBCPP_INTRODUCED_IN_LLVM_22 0
@@ -230,6 +238,12 @@
#define _LIBCPP_AVAILABILITY_HAS_BAD_FUNCTION_CALL_GOOD_WHAT_MESSAGE _LIBCPP_INTRODUCED_IN_LLVM_21
// No attribute, since we've had bad_function_call::what() in the headers before
+// This controls whether we provide messages for `bad_variant_access::what()` that describe the
+// cause of the failure (visit-on-valueless vs. get-with-wrong-alternative). This requires
+// anchoring an internal derived class's vtable, typeinfo, and what() in the dylib.
+#define _LIBCPP_AVAILABILITY_HAS_BAD_VARIANT_ACCESS_GOOD_WHAT_MESSAGE _LIBCPP_INTRODUCED_IN_LLVM_23
+// No attribute, since we've had bad_variant_access in the headers before
+
// This controls the availability of floating-point std::from_chars functions.
// These overloads were added later than the integer overloads.
#define _LIBCPP_AVAILABILITY_HAS_FROM_CHARS_FLOATING_POINT _LIBCPP_INTRODUCED_IN_LLVM_20
diff --git a/libcxx/include/variant b/libcxx/include/variant
index 45462ee8a7713..7caf1e6649602 100644
--- a/libcxx/include/variant
+++ b/libcxx/include/variant
@@ -292,6 +292,17 @@ public:
[[__nodiscard__]] const char* what() const _NOEXCEPT override;
};
+# if _LIBCPP_AVAILABILITY_HAS_BAD_VARIANT_ACCESS_GOOD_WHAT_MESSAGE
+class _LIBCPP_EXPORTED_FROM_ABI __bad_variant_access_with_msg : public bad_variant_access {
+public:
+ _LIBCPP_HIDE_FROM_ABI explicit __bad_variant_access_with_msg(const char* __msg) _NOEXCEPT : __msg_(__msg) {}
+ [[__nodiscard__]] const char* what() const _NOEXCEPT override;
+
+private:
+ const char* __msg_;
+};
+# endif
+
_LIBCPP_END_EXPLICIT_ABI_ANNOTATIONS
_LIBCPP_END_UNVERSIONED_NAMESPACE_STD
@@ -309,11 +320,16 @@ struct __farray {
_LIBCPP_HIDE_FROM_ABI constexpr const _Tp& operator[](size_t __n) const noexcept { return __buf_[__n]; }
};
-[[noreturn]] inline _LIBCPP_HIDE_FROM_ABI void __throw_bad_variant_access() {
+[[noreturn]] inline _LIBCPP_HIDE_FROM_ABI void __throw_bad_variant_access(const char* __msg) {
# if _LIBCPP_HAS_EXCEPTIONS
+# if _LIBCPP_AVAILABILITY_HAS_BAD_VARIANT_ACCESS_GOOD_WHAT_MESSAGE
+ throw __bad_variant_access_with_msg(__msg);
+# else
+ (void)__msg;
throw bad_variant_access();
+# endif
# else
- _LIBCPP_VERBOSE_ABORT("bad_variant_access was thrown in -fno-exceptions mode");
+ _LIBCPP_VERBOSE_ABORT("bad_variant_access was thrown in -fno-exceptions mode: %s", __msg);
# endif
}
@@ -1332,7 +1348,10 @@ template <size_t _Ip, class _Vp>
_LIBCPP_HIDE_FROM_ABI constexpr auto&& __generic_get(_Vp&& __v) {
using __variant_detail::__access::__variant;
if (!std::__holds_alternative<_Ip>(__v)) {
- std::__throw_bad_variant_access();
+ if (__v.valueless_by_exception()) {
+ std::__throw_bad_variant_access("std::get: variant is valueless");
+ }
+ std::__throw_bad_variant_access("std::get: wrong alternative for variant");
}
return __variant::__get_alt<_Ip>(std::forward<_Vp>(__v)).__value;
}
@@ -1569,7 +1588,7 @@ template <class... _Vs>
_LIBCPP_HIDE_FROM_ABI constexpr void __throw_if_valueless(_Vs&&... __vs) {
const bool __valueless = (... || std::__as_variant(__vs).valueless_by_exception());
if (__valueless) {
- std::__throw_bad_variant_access();
+ std::__throw_bad_variant_access("std::visit: variant is valueless");
}
}
diff --git a/libcxx/lib/abi/arm64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.abilist b/libcxx/lib/abi/arm64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.abilist
index da1e340b1d4aa..4493a097adbab 100644
--- a/libcxx/lib/abi/arm64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.abilist
+++ b/libcxx/lib/abi/arm64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.abilist
@@ -373,6 +373,7 @@
{'is_defined': True, 'name': '__ZNKSt16nested_exception14rethrow_nestedEv', 'type': 'FUNC'}
{'is_defined': True, 'name': '__ZNKSt18bad_variant_access4whatEv', 'type': 'FUNC'}
{'is_defined': True, 'name': '__ZNKSt19bad_optional_access4whatEv', 'type': 'FUNC'}
+{'is_defined': True, 'name': '__ZNKSt29__bad_variant_access_with_msg4whatEv', 'type': 'FUNC'}
{'is_defined': True, 'name': '__ZNKSt20bad_array_new_length4whatEv', 'type': 'I'}
{'is_defined': True, 'name': '__ZNKSt3__110__time_put8__do_putEPcRS1_PK2tmcc', 'type': 'FUNC'}
{'is_defined': True, 'name': '__ZNKSt3__110__time_put8__do_putEPwRS1_PK2tmcc', 'type': 'FUNC'}
@@ -2178,6 +2179,7 @@
{'is_defined': True, 'name': '__ZTISt16nested_exception', 'size': 0, 'type': 'OBJECT'}
{'is_defined': True, 'name': '__ZTISt18bad_variant_access', 'size': 0, 'type': 'OBJECT'}
{'is_defined': True, 'name': '__ZTISt19bad_optional_access', 'size': 0, 'type': 'OBJECT'}
+{'is_defined': True, 'name': '__ZTISt29__bad_variant_access_with_msg', 'size': 0, 'type': 'OBJECT'}
{'is_defined': True, 'name': '__ZTISt20bad_array_new_length', 'type': 'I'}
{'is_defined': True, 'name': '__ZTISt8bad_cast', 'type': 'I'}
{'is_defined': True, 'name': '__ZTISt9bad_alloc', 'type': 'I'}
@@ -2392,6 +2394,7 @@
{'is_defined': True, 'name': '__ZTSSt16nested_exception', 'size': 0, 'type': 'OBJECT'}
{'is_defined': True, 'name': '__ZTSSt18bad_variant_access', 'size': 0, 'type': 'OBJECT'}
{'is_defined': True, 'name': '__ZTSSt19bad_optional_access', 'size': 0, 'type': 'OBJECT'}
+{'is_defined': True, 'name': '__ZTSSt29__bad_variant_access_with_msg', 'size': 0, 'type': 'OBJECT'}
{'is_defined': True, 'name': '__ZTSSt20bad_array_new_length', 'type': 'I'}
{'is_defined': True, 'name': '__ZTSSt8bad_cast', 'type': 'I'}
{'is_defined': True, 'name': '__ZTSSt9bad_alloc', 'type': 'I'}
@@ -2564,6 +2567,7 @@
{'is_defined': True, 'name': '__ZTVSt16nested_exception', 'size': 0, 'type': 'OBJECT'}
{'is_defined': True, 'name': '__ZTVSt18bad_variant_access', 'size': 0, 'type': 'OBJECT'}
{'is_defined': True, 'name': '__ZTVSt19bad_optional_access', 'size': 0, 'type': 'OBJECT'}
+{'is_defined': True, 'name': '__ZTVSt29__bad_variant_access_with_msg', 'size': 0, 'type': 'OBJECT'}
{'is_defined': True, 'name': '__ZTVSt20bad_array_new_length', 'type': 'I'}
{'is_defined': True, 'name': '__ZTVSt8bad_cast', 'type': 'I'}
{'is_defined': True, 'name': '__ZTVSt9bad_alloc', 'type': 'I'}
diff --git a/libcxx/lib/abi/i686-linux-android23.libcxxabi.v1.stable.exceptions.nonew.abilist b/libcxx/lib/abi/i686-linux-android23.libcxxabi.v1.stable.exceptions.nonew.abilist
index 814fa26349b3d..2290c53c680e2 100644
--- a/libcxx/lib/abi/i686-linux-android23.libcxxabi.v1.stable.exceptions.nonew.abilist
+++ b/libcxx/lib/abi/i686-linux-android23.libcxxabi.v1.stable.exceptions.nonew.abilist
@@ -10,6 +10,7 @@
{'is_defined': True, 'name': '_ZNKSt16nested_exception14rethrow_nestedEv', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNKSt18bad_variant_access4whatEv', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNKSt19bad_optional_access4whatEv', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNKSt29__bad_variant_access_with_msg4whatEv', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNKSt20bad_array_new_length4whatEv', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNKSt6__ndk110__time_put8__do_putEPcRS1_PK2tmcc', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNKSt6__ndk110__time_put8__do_putEPwRS1_PK2tmcc', 'type': 'FUNC'}
@@ -1840,6 +1841,7 @@
{'is_defined': True, 'name': '_ZTISt16nested_exception', 'size': 8, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTISt18bad_variant_access', 'size': 12, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTISt19bad_optional_access', 'size': 12, 'type': 'OBJECT'}
+{'is_defined': True, 'name': '_ZTISt29__bad_variant_access_with_msg', 'size': 12, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTISt20bad_array_new_length', 'size': 12, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTISt8bad_cast', 'size': 12, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTISt9bad_alloc', 'size': 12, 'type': 'OBJECT'}
@@ -2075,6 +2077,7 @@
{'is_defined': True, 'name': '_ZTSSt16nested_exception', 'size': 21, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTSSt18bad_variant_access', 'size': 23, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTSSt19bad_optional_access', 'size': 24, 'type': 'OBJECT'}
+{'is_defined': True, 'name': '_ZTSSt29__bad_variant_access_with_msg', 'size': 34, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTSSt20bad_array_new_length', 'size': 25, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTSSt8bad_cast', 'size': 12, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTSSt9bad_alloc', 'size': 13, 'type': 'OBJECT'}
@@ -2247,6 +2250,7 @@
{'is_defined': True, 'name': '_ZTVSt16nested_exception', 'size': 16, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTVSt18bad_variant_access', 'size': 20, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTVSt19bad_optional_access', 'size': 20, 'type': 'OBJECT'}
+{'is_defined': True, 'name': '_ZTVSt29__bad_variant_access_with_msg', 'size': 20, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTVSt20bad_array_new_length', 'size': 20, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTVSt8bad_cast', 'size': 20, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTVSt9bad_alloc', 'size': 20, 'type': 'OBJECT'}
diff --git a/libcxx/lib/abi/powerpc-ibm-aix.libcxxabi.v1.stable.exceptions.nonew.abilist b/libcxx/lib/abi/powerpc-ibm-aix.libcxxabi.v1.stable.exceptions.nonew.abilist
index c4b8a79985be5..03a16573c0ad5 100644
--- a/libcxx/lib/abi/powerpc-ibm-aix.libcxxabi.v1.stable.exceptions.nonew.abilist
+++ b/libcxx/lib/abi/powerpc-ibm-aix.libcxxabi.v1.stable.exceptions.nonew.abilist
@@ -3,6 +3,7 @@
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNKSt16nested_exception14rethrow_nestedEv', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNKSt18bad_variant_access4whatEv', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNKSt19bad_optional_access4whatEv', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
+{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNKSt29__bad_variant_access_with_msg4whatEv', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNKSt3__110__time_put8__do_putEPcRS1_PK2tmcc', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNKSt3__110__time_put8__do_putEPwRS1_PK2tmcc', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNKSt3__110error_code7messageEv', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
@@ -938,6 +939,7 @@
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZTISt16nested_exception', 'storage_mapping_class': 'RW', 'type': 'OBJECT'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZTISt18bad_variant_access', 'storage_mapping_class': 'RW', 'type': 'OBJECT'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZTISt19bad_optional_access', 'storage_mapping_class': 'RW', 'type': 'OBJECT'}
+{'import_export': 'EXP', 'is_defined': True, 'name': '_ZTISt29__bad_variant_access_with_msg', 'storage_mapping_class': 'RW', 'type': 'OBJECT'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZTSNSt12experimental15fundamentals_v112bad_any_castE', 'storage_mapping_class': 'RO', 'type': 'OBJECT'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZTSNSt12experimental19bad_optional_accessE', 'storage_mapping_class': 'RO', 'type': 'OBJECT'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZTSNSt3__110istrstreamE', 'storage_mapping_class': 'RO', 'type': 'OBJECT'}
@@ -998,6 +1000,7 @@
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZTSSt16nested_exception', 'storage_mapping_class': 'RO', 'type': 'OBJECT'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZTSSt18bad_variant_access', 'storage_mapping_class': 'RO', 'type': 'OBJECT'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZTSSt19bad_optional_access', 'storage_mapping_class': 'RO', 'type': 'OBJECT'}
+{'import_export': 'EXP', 'is_defined': True, 'name': '_ZTSSt29__bad_variant_access_with_msg', 'storage_mapping_class': 'RO', 'type': 'OBJECT'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZTTNSt3__110istrstreamE', 'storage_mapping_class': 'RW', 'type': 'OBJECT'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZTTNSt3__110ostrstreamE', 'storage_mapping_class': 'RW', 'type': 'OBJECT'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZTTNSt3__19strstreamE', 'storage_mapping_class': 'RW', 'type': 'OBJECT'}
@@ -1061,6 +1064,7 @@
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZTVSt16nested_exception', 'storage_mapping_class': 'RW', 'type': 'OBJECT'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZTVSt18bad_variant_access', 'storage_mapping_class': 'RW', 'type': 'OBJECT'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZTVSt19bad_optional_access', 'storage_mapping_class': 'RW', 'type': 'OBJECT'}
+{'import_export': 'EXP', 'is_defined': True, 'name': '_ZTVSt29__bad_variant_access_with_msg', 'storage_mapping_class': 'RW', 'type': 'OBJECT'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZThn8_NSt3__19strstreamD0Ev', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZThn8_NSt3__19strstreamD1Ev', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZTv0_n12_NSt3__110istrstreamD0Ev', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
diff --git a/libcxx/lib/abi/powerpc64-ibm-aix.libcxxabi.v1.stable.exceptions.nonew.abilist b/libcxx/lib/abi/powerpc64-ibm-aix.libcxxabi.v1.stable.exceptions.nonew.abilist
index 8daf957e6e55f..9da2bfa44b43a 100644
--- a/libcxx/lib/abi/powerpc64-ibm-aix.libcxxabi.v1.stable.exceptions.nonew.abilist
+++ b/libcxx/lib/abi/powerpc64-ibm-aix.libcxxabi.v1.stable.exceptions.nonew.abilist
@@ -3,6 +3,7 @@
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNKSt16nested_exception14rethrow_nestedEv', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNKSt18bad_variant_access4whatEv', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNKSt19bad_optional_access4whatEv', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
+{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNKSt29__bad_variant_access_with_msg4whatEv', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNKSt3__110__time_put8__do_putEPcRS1_PK2tmcc', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNKSt3__110__time_put8__do_putEPwRS1_PK2tmcc', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNKSt3__110error_code7messageEv', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
@@ -938,6 +939,7 @@
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZTISt16nested_exception', 'storage_mapping_class': 'RW', 'type': 'OBJECT'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZTISt18bad_variant_access', 'storage_mapping_class': 'RW', 'type': 'OBJECT'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZTISt19bad_optional_access', 'storage_mapping_class': 'RW', 'type': 'OBJECT'}
+{'import_export': 'EXP', 'is_defined': True, 'name': '_ZTISt29__bad_variant_access_with_msg', 'storage_mapping_class': 'RW', 'type': 'OBJECT'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZTSNSt12experimental15fundamentals_v112bad_any_castE', 'storage_mapping_class': 'RO', 'type': 'OBJECT'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZTSNSt12experimental19bad_optional_accessE', 'storage_mapping_class': 'RO', 'type': 'OBJECT'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZTSNSt3__110istrstreamE', 'storage_mapping_class': 'RO', 'type': 'OBJECT'}
@@ -998,6 +1000,7 @@
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZTSSt16nested_exception', 'storage_mapping_class': 'RO', 'type': 'OBJECT'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZTSSt18bad_variant_access', 'storage_mapping_class': 'RO', 'type': 'OBJECT'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZTSSt19bad_optional_access', 'storage_mapping_class': 'RO', 'type': 'OBJECT'}
+{'import_export': 'EXP', 'is_defined': True, 'name': '_ZTSSt29__bad_variant_access_with_msg', 'storage_mapping_class': 'RO', 'type': 'OBJECT'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZTTNSt3__110istrstreamE', 'storage_mapping_class': 'RW', 'type': 'OBJECT'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZTTNSt3__110ostrstreamE', 'storage_mapping_class': 'RW', 'type': 'OBJECT'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZTTNSt3__19strstreamE', 'storage_mapping_class': 'RW', 'type': 'OBJECT'}
@@ -1061,6 +1064,7 @@
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZTVSt16nested_exception', 'storage_mapping_class': 'RW', 'type': 'OBJECT'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZTVSt18bad_variant_access', 'storage_mapping_class': 'RW', 'type': 'OBJECT'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZTVSt19bad_optional_access', 'storage_mapping_class': 'RW', 'type': 'OBJECT'}
+{'import_export': 'EXP', 'is_defined': True, 'name': '_ZTVSt29__bad_variant_access_with_msg', 'storage_mapping_class': 'RW', 'type': 'OBJECT'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZThn16_NSt3__19strstreamD0Ev', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZThn16_NSt3__19strstreamD1Ev', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZTv0_n24_NSt3__110istrstreamD0Ev', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
diff --git a/libcxx/lib/abi/x86_64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.abilist b/libcxx/lib/abi/x86_64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.abilist
index 281f2f374b78f..5a6fd53e56c78 100644
--- a/libcxx/lib/abi/x86_64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.abilist
+++ b/libcxx/lib/abi/x86_64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.abilist
@@ -372,6 +372,7 @@
{'is_defined': True, 'name': '__ZNKSt16nested_exception14rethrow_nestedEv', 'type': 'FUNC'}
{'is_defined': True, 'name': '__ZNKSt18bad_variant_access4whatEv', 'type': 'FUNC'}
{'is_defined': True, 'name': '__ZNKSt19bad_optional_access4whatEv', 'type': 'FUNC'}
+{'is_defined': True, 'name': '__ZNKSt29__bad_variant_access_with_msg4whatEv', 'type': 'FUNC'}
{'is_defined': True, 'name': '__ZNKSt20bad_array_new_length4whatEv', 'type': 'I'}
{'is_defined': True, 'name': '__ZNKSt3__110__time_put8__do_putEPcRS1_PK2tmcc', 'type': 'FUNC'}
{'is_defined': True, 'name': '__ZNKSt3__110__time_put8__do_putEPwRS1_PK2tmcc', 'type': 'FUNC'}
@@ -2189,6 +2190,7 @@
{'is_defined': True, 'name': '__ZTISt16nested_exception', 'size': 0, 'type': 'OBJECT'}
{'is_defined': True, 'name': '__ZTISt18bad_variant_access', 'size': 0, 'type': 'OBJECT'}
{'is_defined': True, 'name': '__ZTISt19bad_optional_access', 'size': 0, 'type': 'OBJECT'}
+{'is_defined': True, 'name': '__ZTISt29__bad_variant_access_with_msg', 'size': 0, 'type': 'OBJECT'}
{'is_defined': True, 'name': '__ZTISt20bad_array_new_length', 'type': 'I'}
{'is_defined': True, 'name': '__ZTISt8bad_cast', 'type': 'I'}
{'is_defined': True, 'name': '__ZTISt9bad_alloc', 'type': 'I'}
@@ -2412,6 +2414,7 @@
{'is_defined': True, 'name': '__ZTSSt16nested_exception', 'size': 0, 'type': 'OBJECT'}
{'is_defined': True, 'name': '__ZTSSt18bad_variant_access', 'size': 0, 'type': 'OBJECT'}
{'is_defined': True, 'name': '__ZTSSt19bad_optional_access', 'size': 0, 'type': 'OBJECT'}
+{'is_defined': True, 'name': '__ZTSSt29__bad_variant_access_with_msg', 'size': 0, 'type': 'OBJECT'}
{'is_defined': True, 'name': '__ZTSSt20bad_array_new_length', 'type': 'I'}
{'is_defined': True, 'name': '__ZTSSt8bad_cast', 'type': 'I'}
{'is_defined': True, 'name': '__ZTSSt9bad_alloc', 'type': 'I'}
@@ -2584,6 +2587,7 @@
{'is_defined': True, 'name': '__ZTVSt16nested_exception', 'size': 0, 'type': 'OBJECT'}
{'is_defined': True, 'name': '__ZTVSt18bad_variant_access', 'size': 0, 'type': 'OBJECT'}
{'is_defined': True, 'name': '__ZTVSt19bad_optional_access', 'size': 0, 'type': 'OBJECT'}
+{'is_defined': True, 'name': '__ZTVSt29__bad_variant_access_with_msg', 'size': 0, 'type': 'OBJECT'}
{'is_defined': True, 'name': '__ZTVSt20bad_array_new_length', 'type': 'I'}
{'is_defined': True, 'name': '__ZTVSt8bad_cast', 'type': 'I'}
{'is_defined': True, 'name': '__ZTVSt9bad_alloc', 'type': 'I'}
diff --git a/libcxx/lib/abi/x86_64-linux-android23.libcxxabi.v1.stable.exceptions.nonew.abilist b/libcxx/lib/abi/x86_64-linux-android23.libcxxabi.v1.stable.exceptions.nonew.abilist
index 975d7ae118bf5..ffefe12af2149 100644
--- a/libcxx/lib/abi/x86_64-linux-android23.libcxxabi.v1.stable.exceptions.nonew.abilist
+++ b/libcxx/lib/abi/x86_64-linux-android23.libcxxabi.v1.stable.exceptions.nonew.abilist
@@ -10,6 +10,7 @@
{'is_defined': True, 'name': '_ZNKSt16nested_exception14rethrow_nestedEv', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNKSt18bad_variant_access4whatEv', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNKSt19bad_optional_access4whatEv', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNKSt29__bad_variant_access_with_msg4whatEv', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNKSt20bad_array_new_length4whatEv', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNKSt6__ndk110__time_put8__do_putEPcRS1_PK2tmcc', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNKSt6__ndk110__time_put8__do_putEPwRS1_PK2tmcc', 'type': 'FUNC'}
@@ -1838,6 +1839,7 @@
{'is_defined': True, 'name': '_ZTISt16nested_exception', 'size': 16, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTISt18bad_variant_access', 'size': 24, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTISt19bad_optional_access', 'size': 24, 'type': 'OBJECT'}
+{'is_defined': True, 'name': '_ZTISt29__bad_variant_access_with_msg', 'size': 24, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTISt20bad_array_new_length', 'size': 24, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTISt8bad_cast', 'size': 24, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTISt9bad_alloc', 'size': 24, 'type': 'OBJECT'}
@@ -2070,6 +2072,7 @@
{'is_defined': True, 'name': '_ZTSSt16nested_exception', 'size': 21, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTSSt18bad_variant_access', 'size': 23, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTSSt19bad_optional_access', 'size': 24, 'type': 'OBJECT'}
+{'is_defined': True, 'name': '_ZTSSt29__bad_variant_access_with_msg', 'size': 34, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTSSt20bad_array_new_length', 'size': 25, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTSSt8bad_cast', 'size': 12, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTSSt9bad_alloc', 'size': 13, 'type': 'OBJECT'}
@@ -2241,6 +2244,7 @@
{'is_defined': True, 'name': '_ZTVSt16nested_exception', 'size': 32, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTVSt18bad_variant_access', 'size': 40, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTVSt19bad_optional_access', 'size': 40, 'type': 'OBJECT'}
+{'is_defined': True, 'name': '_ZTVSt29__bad_variant_access_with_msg', 'size': 40, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTVSt20bad_array_new_length', 'size': 40, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTVSt8bad_cast', 'size': 40, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTVSt9bad_alloc', 'size': 40, 'type': 'OBJECT'}
diff --git a/libcxx/lib/abi/x86_64-unknown-freebsd.libcxxabi.v1.stable.exceptions.nonew.abilist b/libcxx/lib/abi/x86_64-unknown-freebsd.libcxxabi.v1.stable.exceptions.nonew.abilist
index b27dab3d9203e..05ba5c316352c 100644
--- a/libcxx/lib/abi/x86_64-unknown-freebsd.libcxxabi.v1.stable.exceptions.nonew.abilist
+++ b/libcxx/lib/abi/x86_64-unknown-freebsd.libcxxabi.v1.stable.exceptions.nonew.abilist
@@ -67,6 +67,7 @@
{'is_defined': True, 'name': '_ZNKSt16nested_exception14rethrow_nestedEv', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNKSt18bad_variant_access4whatEv', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNKSt19bad_optional_access4whatEv', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNKSt29__bad_variant_access_with_msg4whatEv', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNKSt3__110__time_put8__do_putEPcRS1_PK2tmcc', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNKSt3__110__time_put8__do_putEPwRS1_PK2tmcc', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNKSt3__110error_code7messageEv', 'type': 'FUNC'}
@@ -1751,6 +1752,7 @@
{'is_defined': True, 'name': '_ZTISt16nested_exception', 'size': 16, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTISt18bad_variant_access', 'size': 24, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTISt19bad_optional_access', 'size': 24, 'type': 'OBJECT'}
+{'is_defined': True, 'name': '_ZTISt29__bad_variant_access_with_msg', 'size': 24, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTSNSt12experimental15fundamentals_v112bad_any_castE', 'size': 50, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTSNSt12experimental19bad_optional_accessE', 'size': 40, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTSNSt3__110__time_getE', 'size': 21, 'type': 'OBJECT'}
@@ -1884,6 +1886,7 @@
{'is_defined': True, 'name': '_ZTSSt16nested_exception', 'size': 21, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTSSt18bad_variant_access', 'size': 23, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTSSt19bad_optional_access', 'size': 24, 'type': 'OBJECT'}
+{'is_defined': True, 'name': '_ZTSSt29__bad_variant_access_with_msg', 'size': 34, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTTNSt3__110istrstreamE', 'size': 32, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTTNSt3__110ostrstreamE', 'size': 32, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTTNSt3__113basic_istreamIcNS_11char_traitsIcEEEE', 'size': 16, 'type': 'OBJECT'}
@@ -2009,6 +2012,7 @@
{'is_defined': True, 'name': '_ZTVSt16nested_exception', 'size': 32, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTVSt18bad_variant_access', 'size': 40, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTVSt19bad_optional_access', 'size': 40, 'type': 'OBJECT'}
+{'is_defined': True, 'name': '_ZTVSt29__bad_variant_access_with_msg', 'size': 40, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZThn16_NSt3__114basic_iostreamIcNS_11char_traitsIcEEED0Ev', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZThn16_NSt3__114basic_iostreamIcNS_11char_traitsIcEEED1Ev', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZThn16_NSt3__19strstreamD0Ev', 'type': 'FUNC'}
diff --git a/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.nonew.abilist b/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.nonew.abilist
index e5372de54c40e..5188294c84818 100644
--- a/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.nonew.abilist
+++ b/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.nonew.abilist
@@ -65,6 +65,7 @@
{'is_defined': True, 'name': '_ZNKSt16nested_exception14rethrow_nestedEv', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNKSt18bad_variant_access4whatEv', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNKSt19bad_optional_access4whatEv', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNKSt29__bad_variant_access_with_msg4whatEv', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNKSt3__110__time_put8__do_putEPcRS1_PK2tmcc', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNKSt3__110__time_put8__do_putEPwRS1_PK2tmcc', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNKSt3__110error_code7messageEv', 'type': 'FUNC'}
@@ -1750,6 +1751,7 @@
{'is_defined': True, 'name': '_ZTISt16nested_exception', 'size': 16, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTISt18bad_variant_access', 'size': 24, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTISt19bad_optional_access', 'size': 24, 'type': 'OBJECT'}
+{'is_defined': True, 'name': '_ZTISt29__bad_variant_access_with_msg', 'size': 24, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTSNSt12experimental15fundamentals_v112bad_any_castE', 'size': 50, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTSNSt12experimental19bad_optional_accessE', 'size': 40, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTSNSt3__110__time_getE', 'size': 21, 'type': 'OBJECT'}
@@ -1883,6 +1885,7 @@
{'is_defined': True, 'name': '_ZTSSt16nested_exception', 'size': 21, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTSSt18bad_variant_access', 'size': 23, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTSSt19bad_optional_access', 'size': 24, 'type': 'OBJECT'}
+{'is_defined': True, 'name': '_ZTSSt29__bad_variant_access_with_msg', 'size': 34, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTTNSt3__110istrstreamE', 'size': 32, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTTNSt3__110ostrstreamE', 'size': 32, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTTNSt3__113basic_istreamIcNS_11char_traitsIcEEEE', 'size': 16, 'type': 'OBJECT'}
@@ -2008,6 +2011,7 @@
{'is_defined': True, 'name': '_ZTVSt16nested_exception', 'size': 32, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTVSt18bad_variant_access', 'size': 40, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZTVSt19bad_optional_access', 'size': 40, 'type': 'OBJECT'}
+{'is_defined': True, 'name': '_ZTVSt29__bad_variant_access_with_msg', 'size': 40, 'type': 'OBJECT'}
{'is_defined': True, 'name': '_ZThn16_NSt3__114basic_iostreamIcNS_11char_traitsIcEEED0Ev', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZThn16_NSt3__114basic_iostreamIcNS_11char_traitsIcEEED1Ev', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZThn16_NSt3__19strstreamD0Ev', 'type': 'FUNC'}
diff --git a/libcxx/src/variant.cpp b/libcxx/src/variant.cpp
index b5462d64fe952..c213cb00feb88 100644
--- a/libcxx/src/variant.cpp
+++ b/libcxx/src/variant.cpp
@@ -12,4 +12,8 @@ namespace std {
const char* bad_variant_access::what() const noexcept { return "bad_variant_access"; }
+#if _LIBCPP_AVAILABILITY_HAS_BAD_VARIANT_ACCESS_GOOD_WHAT_MESSAGE
+const char* __bad_variant_access_with_msg::what() const noexcept { return __msg_; }
+#endif
+
} // namespace std
diff --git a/libcxx/test/libcxx/utilities/variant/variant.bad_variant_access/good_what_message.pass.cpp b/libcxx/test/libcxx/utilities/variant/variant.bad_variant_access/good_what_message.pass.cpp
new file mode 100644
index 0000000000000..707fddca84c27
--- /dev/null
+++ b/libcxx/test/libcxx/utilities/variant/variant.bad_variant_access/good_what_message.pass.cpp
@@ -0,0 +1,92 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, no-exceptions
+
+// Verify that std::bad_variant_access::what() returns a message describing the
+// cause of the failure for std::get and std::visit.
+
+#include <cassert>
+#include <cstring>
+#include <variant>
+
+struct ThrowOnMove {
+ ThrowOnMove() = default;
+ ThrowOnMove(ThrowOnMove&&) { throw 0; }
+};
+
+int main(int, char**) {
+#if _LIBCPP_AVAILABILITY_HAS_BAD_VARIANT_ACCESS_GOOD_WHAT_MESSAGE
+ // std::get<I> on the wrong alternative
+ {
+ std::variant<int, long> v(42);
+ try {
+ (void)std::get<1>(v);
+ assert(false);
+ } catch (const std::bad_variant_access& e) {
+ assert(std::strcmp(e.what(), "std::get: wrong alternative for variant") == 0);
+ }
+ }
+ // std::get<T> on the wrong alternative
+ {
+ std::variant<int, long> v(42);
+ try {
+ (void)std::get<long>(v);
+ assert(false);
+ } catch (const std::bad_variant_access& e) {
+ assert(std::strcmp(e.what(), "std::get: wrong alternative for variant") == 0);
+ }
+ }
+ // std::get<I> on a valueless variant
+ {
+ std::variant<int, ThrowOnMove> v(42);
+ try {
+ v.emplace<1>(ThrowOnMove{});
+ } catch (...) {
+ }
+ assert(v.valueless_by_exception());
+ try {
+ (void)std::get<0>(v);
+ assert(false);
+ } catch (const std::bad_variant_access& e) {
+ assert(std::strcmp(e.what(), "std::get: variant is valueless") == 0);
+ }
+ }
+ // std::get<T> on a valueless variant
+ {
+ std::variant<int, ThrowOnMove> v(42);
+ try {
+ v.emplace<1>(ThrowOnMove{});
+ } catch (...) {
+ }
+ assert(v.valueless_by_exception());
+ try {
+ (void)std::get<int>(v);
+ assert(false);
+ } catch (const std::bad_variant_access& e) {
+ assert(std::strcmp(e.what(), "std::get: variant is valueless") == 0);
+ }
+ }
+ // std::visit on a valueless variant
+ {
+ std::variant<int, ThrowOnMove> v(42);
+ try {
+ v.emplace<1>(ThrowOnMove{});
+ } catch (...) {
+ }
+ assert(v.valueless_by_exception());
+ try {
+ std::visit([](auto&&) {}, v);
+ assert(false);
+ } catch (const std::bad_variant_access& e) {
+ assert(std::strcmp(e.what(), "std::visit: variant is valueless") == 0);
+ }
+ }
+#endif
+ return 0;
+}
More information about the libcxx-commits
mailing list