[PATCH] [libcxx] Fix PR22806 - Tuple incorrectly selects copy/move constructor when storing nested tuple-like types.
Eric Fiselier
eric at efcs.ca
Mon Mar 9 11:14:11 PDT 2015
Hi mclow.lists, ldionne, K-ballo,
There are two conflicting constructors in tuple:
```
template <class ..._Up>
tuple(_Up&&...) // Construct from elements.
template <class _Tuple>
tuple(_Tuple&&) // copy/move constructor.
```
When the length of the tuple is 1 and the first element is a tuple then we can incorrectly select the copy/move constructor. This patch adds more SFINAE to try and prevent this.
This patch likely needs more work.
http://reviews.llvm.org/D8178
Files:
include/tuple
test/std/utilities/tuple/tuple.tuple/tuple.cnstr/tuple_like_sfinae.pass.cpp
Index: include/tuple
===================================================================
--- include/tuple
+++ include/tuple
@@ -500,6 +500,7 @@
class _LIBCPP_TYPE_VIS_ONLY tuple
{
typedef __tuple_impl<typename __make_tuple_indices<sizeof...(_Tp)>::type, _Tp...> base;
+ typedef typename tuple_element<0, __tuple_types<_Tp...>>::type _First;
base base_;
@@ -655,6 +656,8 @@
template <class _Tuple,
typename enable_if
<
+ !(sizeof...(_Tp) == 1 &&
+ __tuple_convertible<tuple<_Tuple>, __tuple_types<_First>>::value) &&
__tuple_convertible<_Tuple, tuple>::value,
bool
>::type = false
@@ -666,6 +669,9 @@
template <class _Tuple,
typename enable_if
<
+ !(sizeof...(_Tp) == 1 &&
+ (__tuple_convertible<tuple<_Tuple>, __tuple_types<_First>>::value ||
+ __tuple_constructible<tuple<_Tuple>, __tuple_types<_First>>::value)) &&
__tuple_constructible<_Tuple, tuple>::value &&
!__tuple_convertible<_Tuple, tuple>::value,
bool
@@ -679,6 +685,8 @@
template <class _Alloc, class _Tuple,
class = typename enable_if
<
+ !(sizeof...(_Tp) == 1 &&
+ __tuple_convertible<tuple<_Tuple>, __tuple_types<_First>>::value) &&
__tuple_convertible<_Tuple, tuple>::value
>::type
>
Index: test/std/utilities/tuple/tuple.tuple/tuple.cnstr/tuple_like_sfinae.pass.cpp
===================================================================
--- /dev/null
+++ test/std/utilities/tuple/tuple.tuple/tuple.cnstr/tuple_like_sfinae.pass.cpp
@@ -0,0 +1,44 @@
+#include <cassert>
+#include <tuple>
+#include <memory>
+
+#include "tracked_value.h"
+
+int main()
+{
+ {
+ TrackedValue v;
+ std::tuple<TrackedValue> t1(v);
+ // This selects the wrong constructor and constructs std::tuple<Tracked>&&
+ // from a temporary.
+ std::tuple<std::tuple<TrackedValue>&&> t2(std::move(t1));
+ // This moves from the reference constructed from the temporary.
+ std::tuple<std::tuple<TrackedValue>> t3(std::move(t2));
+ }
+ {
+ TrackedValue v;
+ std::tuple<TrackedValue> t1(v);
+ std::tuple<std::tuple<TrackedValue> const &> t2(t1);
+ std::tuple<std::tuple<TrackedValue>> t3(t2);
+ }
+ {
+ TrackedValue v;
+ std::tuple<TrackedValue> t1(v);
+ std::tuple<std::tuple<TrackedValue> &> t2(t1);
+ std::tuple<std::tuple<TrackedValue>> t3(t2);
+ }
+ {
+ TrackedValue v;
+ std::tuple<TrackedValue> t1(v);
+ std::tuple<std::tuple<TrackedValue>&&> t2(std::move(t1));
+ std::allocator<void> a;
+ std::tuple<std::tuple<TrackedValue>> t3(std::allocator_arg, a, std::move(t2));
+ }
+ {
+ TrackedValue v;
+ std::tuple<TrackedValue> t1(v);
+ std::tuple<std::tuple<TrackedValue> const &> t2(t1);
+ std::allocator<void> a;
+ std::tuple<std::tuple<TrackedValue>> t3(std::allocator_arg, a, t2);
+ }
+}
EMAIL PREFERENCES
http://reviews.llvm.org/settings/panel/emailpreferences/
-------------- next part --------------
A non-text attachment was scrubbed...
Name: D8178.21501.patch
Type: text/x-patch
Size: 3270 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20150309/36ffb401/attachment.bin>
More information about the cfe-commits
mailing list