[libcxx-commits] [libcxx] [libcxx] Enrich message for std::bad_variant_access exception (PR #196495)

Louis Dionne via libcxx-commits libcxx-commits at lists.llvm.org
Wed Jun 17 09:28:59 PDT 2026


================
@@ -309,11 +322,11 @@ 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
-  throw bad_variant_access();
+  throw __bad_variant_access_with_msg(__msg);
----------------
ldionne wrote:

Are we allowed to actually throw something that is not *exactly* `bad_variant_access`? Doesn't that break code like this?

```c++
#include <variant>
#include <cassert>
#include <typeinfo>

int main() {
  std::variant<int, float> v(1);
  try {
    (void)std::get<float>(v);
  } catch (std::bad_variant_access const& exc) {
    assert(typeid(exc) == typeid(std::bad_variant_access));
  }
}
```

I tried adding that test in the suite and it does fail. The only question is whether users are allowed to rely on it, but I think they are. In practice, I'd expect this shows up way more subtly than `assert(typeid(...) == typeid(...))`, but you get the point. `get` clearly says: https://eel.is/c++draft/variant#get-7

> Effects: If v.index() is I, returns a reference to the object stored in the variant[.](https://eel.is/c++draft/variant#get-7.sentence-1) Otherwise, throws an exception of type bad_variant_access[.](https://eel.is/c++draft/variant#get-7.sentence-2)

So, sadly, I don't think this derived class trick is legal. @philnik777 WDYT?

https://github.com/llvm/llvm-project/pull/196495


More information about the libcxx-commits mailing list