[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