Here's a short repro: #include <variant> struct V : std::variant<int> { using std::variant<int>::variant; }; namespace std { template <> struct variant_size<V> : integral_constant<size_t, 1> { }; template <> struct variant_alternative<0, V> { using type = int; }; } V v = 42; int i = std::visit([](int){ return 17;}, v); This worked fine in gcc 8, but breaks in gcc 9 with: In file included from <source>:1: /opt/compiler-explorer/gcc-9.1.0/include/c++/9.1.0/variant: In instantiation of 'constexpr const bool std::__detail::__variant::_Extra_visit_slot_needed<int, V&>::value': /opt/compiler-explorer/gcc-9.1.0/include/c++/9.1.0/variant:809:50: required from 'constexpr const int std::__detail::__variant::_Multi_array<int (*)(<lambda(int)>&&, V&), 1>::__do_cookie' /opt/compiler-explorer/gcc-9.1.0/include/c++/9.1.0/variant:821:53: required from 'struct std::__detail::__variant::_Multi_array<int (*)(<lambda(int)>&&, V&), 1>' /opt/compiler-explorer/gcc-9.1.0/include/c++/9.1.0/variant:1016:36: required from 'struct std::__detail::__variant::__gen_vtable<true, int, <lambda(int)>&&, V&>' /opt/compiler-explorer/gcc-9.1.0/include/c++/9.1.0/variant:1637:23: required from 'constexpr decltype(auto) std::__do_visit(_Visitor&&, _Variants&& ...) [with bool __use_index = false; bool __same_return_types = true; _Visitor = <lambda(int)>; _Variants = {V&}]' /opt/compiler-explorer/gcc-9.1.0/include/c++/9.1.0/variant:1653:24: required from 'constexpr decltype(auto) std::visit(_Visitor&&, _Variants&& ...) [with _Visitor = <lambda(int)>; _Variants = {V&}]' <source>:21:43: required from here /opt/compiler-explorer/gcc-9.1.0/include/c++/9.1.0/variant:778:5: error: incomplete type 'std::__detail::__variant::_Extra_visit_slot_needed<int, V&>::_Variant_never_valueless<V>' used in nested name specifier 778 | && !_Variant_never_valueless<__remove_cvref_t<_Variant>>::value; | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ I realize that this kind of stuff isn't technically or officially sanctioned -- but doing this makes it very convenient to write an easy-to-use recursive variant without having to implement our own variant. Tim says you should call this NAD, but I'm being pretty optimistic :-)
This is all it takes to compile your example: --- a/libstdc++-v3/include/std/variant +++ b/libstdc++-v3/include/std/variant @@ -795,7 +795,7 @@ namespace __variant template <typename _Maybe_variant_cookie, typename _Variant> struct _Extra_visit_slot_needed { - template <typename> struct _Variant_never_valueless; + template <typename> struct _Variant_never_valueless : false_type { }; template <typename... _Types> struct _Variant_never_valueless<variant<_Types...>> This just assumes that unrecognized types are not never-valueless variants, which means some extra code gets generated to handle the valueless case even if your variant base class will never be valueless. I haven't considered if anything else would break by doing that.
What if we did something like (using pretty names for a sec): template <typename _Maybe_variant_cookie, typename _Variant> struct _Extra_visit_slot_needed { template <typename... _Types> static bool_constant<__never_valueless<_Types...>()> __impl(const variant<_Types...>&); static false_type __impl(...); using _Variant_never_valueless = decltype(__impl(declval<_Variant>())); static constexpr bool value = (is_same_v<_Maybe_variant_cookie, __variant_cookie> || is_same_v<_Maybe_variant_cookie, __variant_idx_cookie>) && !_Variant_never_valueless::value; }; This should (modulo typos) work for real variant instantiations and also anything that inherits from some variant instantiation?
https://wg21.link/LWG3052 would forbid us from supporting this.
GCC 9.2 has been released.
GCC 9.3.0 has been released, adjusting target milestone.
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p2162r2.html says we should support inherited variants.
Implemented downstream: https://gitlab.com/jonathan-wakely/gcc/-/commit/484308ad163862632ae7e710c5d909be385450aa
Corrected URL for downstream fix: https://gitlab.com/jonathan-wakely/gcc/-/commit/486d89e403a18ef78f05f2efb1bc86bbd396899c
The master branch has been updated by Jonathan Wakely <redi@gcc.gnu.org>: https://gcc.gnu.org/g:c46ecb0112e91c80ee111439e79a58a953e4479d commit r12-4067-gc46ecb0112e91c80ee111439e79a58a953e4479d Author: Jonathan Wakely <jwakely@redhat.com> Date: Mon Apr 19 14:49:12 2021 +0100 libstdc++: Allow visiting inherited variants [PR 90943] Implement the changes from P2162R2 (as a DR for C++17). Signed-off-by: Jonathan Wakely <jwakely@redhat.com> libstdc++-v3/ChangeLog: PR libstdc++/90943 * include/std/variant (__cpp_lib_variant): Update value. (__detail::__variant::__as): New helpers implementing the as-variant exposition-only function templates. (visit, visit<R>): Use __as to upcast the variant parameters. * include/std/version (__cpp_lib_variant): Update value. * testsuite/20_util/variant/visit_inherited.cc: New test.
Done for GCC 12, but I intend to backport it.
The releases/gcc-11 branch has been updated by Jonathan Wakely <redi@gcc.gnu.org>: https://gcc.gnu.org/g:90b94ca5a2ddd7834afff9ad5e1afff5554e0752 commit r11-9831-g90b94ca5a2ddd7834afff9ad5e1afff5554e0752 Author: Jonathan Wakely <jwakely@redhat.com> Date: Mon Apr 19 14:49:12 2021 +0100 libstdc++: Allow visiting inherited variants [PR 90943] Implement the changes from P2162R2 (as a DR for C++17). Signed-off-by: Jonathan Wakely <jwakely@redhat.com> libstdc++-v3/ChangeLog: PR libstdc++/90943 * include/std/variant (__cpp_lib_variant): Update value. (__detail::__variant::__as): New helpers implementing the as-variant exposition-only function templates. (visit, visit<R>): Use __as to upcast the variant parameters. * include/std/version (__cpp_lib_variant): Update value. * testsuite/20_util/variant/visit_inherited.cc: New test. (cherry picked from commit c46ecb0112e91c80ee111439e79a58a953e4479d)
Fixed for 11.3