[gcc r10-9937] libstdc++: Do not use deduced return type for std::visit [PR 100384]
Jonathan Wakely
redi@gcc.gnu.org
Fri Jun 18 12:56:28 GMT 2021
https://gcc.gnu.org/g:8ad4d9b46944db1be6f1b216b5b8e74bd9f66937
commit r10-9937-g8ad4d9b46944db1be6f1b216b5b8e74bd9f66937
Author: Jonathan Wakely <jwakely@redhat.com>
Date: Tue May 4 12:16:46 2021 +0100
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.
(cherry picked from commit af5b2b911dd80ae9cc87404b7e7ab807cf6655d4)
Diff:
---
libstdc++-v3/include/std/variant | 28 ++++++++++++++++++++----
libstdc++-v3/testsuite/20_util/variant/100384.cc | 9 ++++++++
2 files changed, 33 insertions(+), 4 deletions(-)
diff --git a/libstdc++-v3/include/std/variant b/libstdc++-v3/include/std/variant
index 0a754fb4196..5f76d76490e 100644
--- a/libstdc++-v3/include/std/variant
+++ b/libstdc++-v3/include/std/variant
@@ -1053,6 +1053,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
@@ -1238,7 +1257,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> && ...)
@@ -1704,14 +1724,14 @@ namespace __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>;
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 00000000000..4866aa017ff
--- /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);
More information about the Libstdc++-cvs
mailing list