aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVille Voutilainen <ville.voutilainen@gmail.com>2019-04-08 22:45:48 +0300
committerVille Voutilainen <ville@gcc.gnu.org>2019-04-08 22:45:48 +0300
commit3d01c7c2f20ffc062d01a525b8e567931c2b089c (patch)
treebfb9c683a02f50f55e7e54b9010f95a168dd8b3e
parent15f4769a12dd1640fcf6608c34eea46d8da86fbb (diff)
downloadgcc-3d01c7c2f20ffc062d01a525b8e567931c2b089c.zip
gcc-3d01c7c2f20ffc062d01a525b8e567931c2b089c.tar.gz
gcc-3d01c7c2f20ffc062d01a525b8e567931c2b089c.tar.bz2
Fix visit<R> for variant.
* include/std/variant (__do_visit): Add a template parameter for enforcing same return types for visit. (__gen_vtable_impl): Likewise. (_S_apply_single_alt): Adjust. (__visit_invoke_impl): New. Handle casting to void. (__do_visit_invoke): New. Enforces same return types. (__do_visit_invoke_r): New. Converts return types. (__visit_invoke): Adjust. (__gen_vtable): Add a template parameter for enforcing same return types for visit. * testsuite/20_util/variant/visit_r.cc: Add a test for a visitor with different return types. * testsuite/20_util/variant/visit_neg.cc: New. Ensures that visitors with different return types don't accidentally compile with regular visitation. From-SVN: r270216
-rw-r--r--libstdc++-v3/ChangeLog19
-rw-r--r--libstdc++-v3/include/std/variant78
-rw-r--r--libstdc++-v3/testsuite/20_util/variant/visit_neg.cc45
-rw-r--r--libstdc++-v3/testsuite/20_util/variant/visit_r.cc14
4 files changed, 140 insertions, 16 deletions
diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog
index 7ea0fd0..f363c44 100644
--- a/libstdc++-v3/ChangeLog
+++ b/libstdc++-v3/ChangeLog
@@ -1,3 +1,22 @@
+2019-04-08 Ville Voutilainen <ville.voutilainen@gmail.com>
+
+ Fix visit<R> for variant.
+ * include/std/variant (__do_visit): Add a template parameter
+ for enforcing same return types for visit.
+ (__gen_vtable_impl): Likewise.
+ (_S_apply_single_alt): Adjust.
+ (__visit_invoke_impl): New. Handle casting to void.
+ (__do_visit_invoke): New. Enforces same return types.
+ (__do_visit_invoke_r): New. Converts return types.
+ (__visit_invoke): Adjust.
+ (__gen_vtable): Add a template parameter for enforcing
+ same return types for visit.
+ * testsuite/20_util/variant/visit_r.cc: Add a test for a visitor with
+ different return types.
+ * testsuite/20_util/variant/visit_neg.cc: New. Ensures that
+ visitors with different return types don't accidentally
+ compile with regular visitation.
+
2019-04-08 Christophe Lyon <christophe.lyon@linaro.org>
* testsuite/27_io/filesystem/iterators/caching.cc: Add
diff --git a/libstdc++-v3/include/std/variant b/libstdc++-v3/include/std/variant
index fdf04cf..7bab472 100644
--- a/libstdc++-v3/include/std/variant
+++ b/libstdc++-v3/include/std/variant
@@ -138,7 +138,9 @@ namespace __variant
constexpr variant_alternative_t<_Np, variant<_Types...>> const&&
get(const variant<_Types...>&&);
- template<bool __use_index=false, typename _Visitor, typename... _Variants>
+ template<bool __use_index=false,
+ bool __same_return_types = true,
+ typename _Visitor, typename... _Variants>
constexpr decltype(auto)
__do_visit(_Visitor&& __visitor, _Variants&&... __variants);
@@ -868,12 +870,15 @@ namespace __variant
// tuple<V1&&, V2&&>, std::index_sequence<1, 2>>
// The returned multi-dimensional vtable can be fast accessed by the visitor
// using index calculation.
- template<typename _Array_type, typename _Variant_tuple, typename _Index_seq>
+ template<bool __same_return_types,
+ typename _Array_type, typename _Variant_tuple, typename _Index_seq>
struct __gen_vtable_impl;
- template<typename _Result_type, typename _Visitor, size_t... __dimensions,
+ template<bool __same_return_types,
+ typename _Result_type, typename _Visitor, size_t... __dimensions,
typename... _Variants, size_t... __indices>
struct __gen_vtable_impl<
+ __same_return_types,
_Multi_array<_Result_type (*)(_Visitor, _Variants...), __dimensions...>,
tuple<_Variants...>, std::index_sequence<__indices...>>
{
@@ -915,10 +920,12 @@ namespace __variant
if constexpr (__do_cookie)
{
__element = __gen_vtable_impl<
+ __same_return_types,
_Tp,
tuple<_Variants...>,
std::index_sequence<__indices..., __index>>::_S_apply();
*__cookie_element = __gen_vtable_impl<
+ __same_return_types,
_Tp,
tuple<_Variants...>,
std::index_sequence<__indices..., variant_npos>>::_S_apply();
@@ -926,15 +933,18 @@ namespace __variant
else
{
__element = __gen_vtable_impl<
+ __same_return_types,
remove_reference_t<decltype(__element)>, tuple<_Variants...>,
std::index_sequence<__indices..., __index>>::_S_apply();
}
}
};
- template<typename _Result_type, typename _Visitor, typename... _Variants,
+ template<bool __same_return_types,
+ typename _Result_type, typename _Visitor, typename... _Variants,
size_t... __indices>
struct __gen_vtable_impl<
+ __same_return_types,
_Multi_array<_Result_type (*)(_Visitor, _Variants...)>,
tuple<_Variants...>, std::index_sequence<__indices...>>
{
@@ -952,25 +962,56 @@ namespace __variant
}
static constexpr decltype(auto)
- __visit_invoke(_Visitor&& __visitor, _Variants... __vars)
+ __visit_invoke_impl(_Visitor&& __visitor, _Variants... __vars)
{
- if constexpr (is_same_v<_Result_type, __variant_idx_cookie>)
- return std::__invoke(std::forward<_Visitor>(__visitor),
+ if constexpr (is_same_v<_Result_type, __variant_idx_cookie>)
+ return std::__invoke(std::forward<_Visitor>(__visitor),
+ __element_by_index_or_cookie<__indices>(
+ std::forward<_Variants>(__vars))...,
+ integral_constant<size_t, __indices>()...);
+ else if constexpr (!__same_return_types &&
+ std::is_void_v<_Result_type>)
+ return (void)std::__invoke(std::forward<_Visitor>(__visitor),
__element_by_index_or_cookie<__indices>(
- std::forward<_Variants>(__vars))...,
- integral_constant<size_t, __indices>()...);
+ std::forward<_Variants>(__vars))...);
else
return std::__invoke(std::forward<_Visitor>(__visitor),
__element_by_index_or_cookie<__indices>(
std::forward<_Variants>(__vars))...);
}
+ static constexpr decltype(auto)
+ __do_visit_invoke(_Visitor&& __visitor, _Variants... __vars)
+ {
+ return __visit_invoke_impl(std::forward<_Visitor>(__visitor),
+ std::forward<_Variants>(__vars)...);
+ }
+
+ static constexpr _Result_type
+ __do_visit_invoke_r(_Visitor&& __visitor, _Variants... __vars)
+ {
+ return __visit_invoke_impl(std::forward<_Visitor>(__visitor),
+ std::forward<_Variants>(__vars)...);
+ }
+
+ static constexpr decltype(auto)
+ __visit_invoke(_Visitor&& __visitor, _Variants... __vars)
+ {
+ if constexpr (__same_return_types)
+ return __do_visit_invoke(std::forward<_Visitor>(__visitor),
+ std::forward<_Variants>(__vars)...);
+ else
+ return __do_visit_invoke_r(std::forward<_Visitor>(__visitor),
+ std::forward<_Variants>(__vars)...);
+ }
+
static constexpr auto
_S_apply()
{ return _Array_type{&__visit_invoke}; }
};
- template<typename _Result_type, typename _Visitor, typename... _Variants>
+ template<bool __same_return_types,
+ typename _Result_type, typename _Visitor, typename... _Variants>
struct __gen_vtable
{
using _Func_ptr = _Result_type (*)(_Visitor&&, _Variants...);
@@ -981,7 +1022,8 @@ namespace __variant
static constexpr _Array_type
_S_apply()
{
- return __gen_vtable_impl<_Array_type, tuple<_Variants...>,
+ return __gen_vtable_impl<__same_return_types,
+ _Array_type, tuple<_Variants...>,
std::index_sequence<>>::_S_apply();
}
@@ -1582,7 +1624,9 @@ namespace __variant
std::get<0>(std::forward<_Variants>(__variants))...);
}
- template<bool __use_index, typename _Visitor, typename... _Variants>
+ template<bool __use_index,
+ bool __same_return_types,
+ typename _Visitor, typename... _Variants>
constexpr decltype(auto)
__do_visit(_Visitor&& __visitor, _Variants&&... __variants)
{
@@ -1592,6 +1636,7 @@ namespace __variant
std::forward<_Variants>(__variants)...));
constexpr auto& __vtable = __detail::__variant::__gen_vtable<
+ __same_return_types,
_Result_type, _Visitor&&, _Variants&&...>::_S_vtable;
auto __func_ptr = __vtable._M_access(__variants.index()...);
@@ -1618,12 +1663,13 @@ namespace __variant
if ((__variants.valueless_by_exception() || ...))
__throw_bad_variant_access("Unexpected index");
+
if constexpr (std::is_void_v<_Res>)
- (void) __do_visit(std::forward<_Visitor>(__visitor),
- std::forward<_Variants>(__variants)...);
+ (void) __do_visit<false, false>(std::forward<_Visitor>(__visitor),
+ std::forward<_Variants>(__variants)...);
else
- return __do_visit(std::forward<_Visitor>(__visitor),
- std::forward<_Variants>(__variants)...);
+ return __do_visit<false, false>(std::forward<_Visitor>(__visitor),
+ std::forward<_Variants>(__variants)...);
}
#endif
diff --git a/libstdc++-v3/testsuite/20_util/variant/visit_neg.cc b/libstdc++-v3/testsuite/20_util/variant/visit_neg.cc
new file mode 100644
index 0000000..ae6fdd1
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/variant/visit_neg.cc
@@ -0,0 +1,45 @@
+// Copyright (C) 2019 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <variant>
+#include <testsuite_hooks.h>
+
+// { dg-error "invalid conversion" "" { target *-*-* } 0 }
+// { dg-prune-output "in 'constexpr' expansion" }
+
+void
+test01()
+{
+ {
+ struct Visitor
+ {
+ double operator()(double) {return 0.02;}
+ void operator()(int) {}
+ };
+ std::variant<int, double> v;
+ std::visit(Visitor(), v);
+ }
+}
+
+int
+main()
+{
+ test01();
+}
diff --git a/libstdc++-v3/testsuite/20_util/variant/visit_r.cc b/libstdc++-v3/testsuite/20_util/variant/visit_r.cc
index 5eed0cf..55f5f8b 100644
--- a/libstdc++-v3/testsuite/20_util/variant/visit_r.cc
+++ b/libstdc++-v3/testsuite/20_util/variant/visit_r.cc
@@ -42,8 +42,22 @@ test01()
static_assert(std::is_void_v<decltype(std::visit<void>(Visitor{}, v1, v2))>);
}
+void test02()
+{
+ struct Visitor
+ {
+ int operator()(double) {return 42;}
+ double operator()(int) {return 0.02;}
+ };
+ std::variant<int, double> v;
+ std::visit<int>(Visitor(), v);
+ std::visit<const void>(Visitor(), v);
+}
+
+
int
main()
{
test01();
+ test02();
}