diff options
author | Jonathan Wakely <jwakely@redhat.com> | 2021-05-04 12:16:46 +0100 |
---|---|---|
committer | Jonathan Wakely <jwakely@redhat.com> | 2021-05-04 12:16:46 +0100 |
commit | af5b2b911dd80ae9cc87404b7e7ab807cf6655d4 (patch) | |
tree | b28d4349aad905b711cb7166bdcf7c50cf437efe | |
parent | ad0a3be4df5eecc79075d899fd79179d0f61270e (diff) | |
download | gcc-af5b2b911dd80ae9cc87404b7e7ab807cf6655d4.zip gcc-af5b2b911dd80ae9cc87404b7e7ab807cf6655d4.tar.gz gcc-af5b2b911dd80ae9cc87404b7e7ab807cf6655d4.tar.bz2 |
libstdc++: Do not use deduced return type for std::visit [PR 100384]
This avoids errors outside the immediate context when std::visit is an
overload candidate because of ADL, but not actually viable.
The solution is to give std::visit a non-deduced return type. New
helpers are introduced for that, and existing ones refactored slightly.
libstdc++-v3/ChangeLog:
PR libstdc++/100384
* include/std/variant (__get_t): New alias template yielding the
return type of std::get<N> on a variant.
(__visit_result_t): New alias template yielding the result of
std::visit.
(__same_types): Move into namespace __detail::__variant.
(__check_visitor_results): Likewise. Use __invoke_result_t and
__get_t.
(__check_visitor_result): Remove.
(visit): Use __visit_result_t for return type.
* testsuite/20_util/variant/100384.cc: New test.
-rw-r--r-- | libstdc++-v3/include/std/variant | 50 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/20_util/variant/100384.cc | 9 |
2 files changed, 34 insertions, 25 deletions
diff --git a/libstdc++-v3/include/std/variant b/libstdc++-v3/include/std/variant index 1ef9b97..9b2bc44 100644 --- a/libstdc++-v3/include/std/variant +++ b/libstdc++-v3/include/std/variant @@ -1063,6 +1063,25 @@ namespace __variant std::index_sequence<__indices...>> : _Base_dedup<__indices, __poison_hash<remove_const_t<_Types>>>... { }; + template<size_t _Np, typename _Variant> + using __get_t = decltype(std::get<_Np>(std::declval<_Variant>())); + + // Return type of std::visit. + template<typename _Visitor, typename... _Variants> + using __visit_result_t + = invoke_result_t<_Visitor, __get_t<0, _Variants>...>; + + template<typename _Tp, typename... _Types> + constexpr inline bool __same_types = (is_same_v<_Tp, _Types> && ...); + + template <typename _Visitor, typename _Variant, size_t... _Idxs> + constexpr bool __check_visitor_results(std::index_sequence<_Idxs...>) + { + return __same_types< + invoke_result_t<_Visitor, __get_t<_Idxs, _Variant>>... + >; + } + } // namespace __variant } // namespace __detail @@ -1248,7 +1267,8 @@ namespace __variant #endif template<typename _Visitor, typename... _Variants> - constexpr decltype(auto) visit(_Visitor&&, _Variants&&...); + constexpr __detail::__variant::__visit_result_t<_Visitor, _Variants...> + visit(_Visitor&&, _Variants&&...); template<typename... _Types> inline enable_if_t<(is_move_constructible_v<_Types> && ...) @@ -1715,41 +1735,21 @@ namespace __variant std::forward<_Variants>(__variants)...); } - template<typename _Tp, typename... _Types> - constexpr inline bool __same_types = (is_same_v<_Tp, _Types> && ...); - - template <size_t _Idx, typename _Visitor, typename _Variant> - decltype(auto) - __check_visitor_result(_Visitor&& __vis, _Variant&& __variant) - { - return std::__invoke(std::forward<_Visitor>(__vis), - std::get<_Idx>(std::forward<_Variant>(__variant))); - } - - template <typename _Visitor, typename _Variant, size_t... _Idxs> - constexpr bool __check_visitor_results(std::index_sequence<_Idxs...>) - { - return __same_types<decltype(__check_visitor_result<_Idxs>( - std::declval<_Visitor>(), - std::declval<_Variant>()))...>; - } - - template<typename _Visitor, typename... _Variants> - constexpr decltype(auto) + constexpr __detail::__variant::__visit_result_t<_Visitor, _Variants...> visit(_Visitor&& __visitor, _Variants&&... __variants) { if ((__variants.valueless_by_exception() || ...)) __throw_bad_variant_access("std::visit: variant is valueless"); - using _Result_type = std::invoke_result_t<_Visitor, - decltype(std::get<0>(std::declval<_Variants>()))...>; + using _Result_type + = __detail::__variant::__visit_result_t<_Visitor, _Variants...>; using _Tag = __detail::__variant::__deduce_visit_result<_Result_type>; if constexpr (sizeof...(_Variants) == 1) { - constexpr bool __visit_rettypes_match = + constexpr bool __visit_rettypes_match = __detail::__variant:: __check_visitor_results<_Visitor, _Variants...>( std::make_index_sequence< std::variant_size<remove_reference_t<_Variants>...>::value>()); diff --git a/libstdc++-v3/testsuite/20_util/variant/100384.cc b/libstdc++-v3/testsuite/20_util/variant/100384.cc new file mode 100644 index 0000000..4866aa0 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/variant/100384.cc @@ -0,0 +1,9 @@ +// { dg-do compile { target c++17 } } + +#include <variant> + +int visit(int*, std::true_type) { return 0; } + +const std::true_type dat; + +int i = visit(nullptr, dat); |