[libcxx] r213888 - D4451: Fix copy/move issues casude by __tuple_leafs's converting constructor

Eric Fiselier eric at efcs.ca
Thu Jul 24 11:48:35 PDT 2014


Author: ericwf
Date: Thu Jul 24 13:48:34 2014
New Revision: 213888

URL: http://llvm.org/viewvc/llvm-project?rev=213888&view=rev
Log:
D4451: Fix copy/move issues casude by __tuple_leafs's converting constructor

Modified:
    libcxx/trunk/include/__tuple
    libcxx/trunk/include/tuple
    libcxx/trunk/test/utilities/tuple/tuple.tuple/tuple.cnstr/const_Types.pass.cpp
    libcxx/trunk/test/utilities/tuple/tuple.tuple/tuple.cnstr/move.pass.cpp
    libcxx/trunk/test/utilities/tuple/tuple.tuple/tuple.elem/tuple.by.type1.fail.cpp
    libcxx/trunk/test/utilities/utility/pairs/pair.astuple/pairs.by.type1.fail.cpp

Modified: libcxx/trunk/include/__tuple
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/__tuple?rev=213888&r1=213887&r2=213888&view=diff
==============================================================================
--- libcxx/trunk/include/__tuple (original)
+++ libcxx/trunk/include/__tuple Thu Jul 24 13:48:34 2014
@@ -27,6 +27,32 @@
 
 _LIBCPP_BEGIN_NAMESPACE_STD
 
+// __lazy_and
+
+template <bool _Last, class ..._Preds>
+struct __lazy_and_impl;
+
+template <class ..._Preds>
+struct __lazy_and_impl<false, _Preds...> : false_type {};
+
+template <>
+struct __lazy_and_impl<true> : true_type {};
+
+template <class _Pred>
+struct __lazy_and_impl<true, _Pred> : integral_constant<bool, _Pred::type::value> {};
+
+template <class _Hp, class ..._Tp>
+struct __lazy_and_impl<true, _Hp, _Tp...> : __lazy_and_impl<_Hp::type::value, _Tp...> {};
+
+template <class _P1, class ..._Pr>
+struct __lazy_and : __lazy_and_impl<_P1::type::value, _Pr...> {};
+
+// __lazy_not
+
+template <class _Pred>
+struct __lazy_not : integral_constant<bool, !_Pred::type::value> {};
+
+
 template <class _Tp> class _LIBCPP_TYPE_VIS_ONLY tuple_size;
 
 template <class _Tp>

Modified: libcxx/trunk/include/tuple
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/tuple?rev=213888&r1=213887&r2=213888&view=diff
==============================================================================
--- libcxx/trunk/include/tuple (original)
+++ libcxx/trunk/include/tuple Thu Jul 24 13:48:34 2014
@@ -210,7 +210,13 @@ public:
               "Attempted to default construct a reference element in a tuple");}
 
     template <class _Tp,
-              class = typename enable_if<is_constructible<_Hp, _Tp>::value>::type>
+              class = typename enable_if<
+                  __lazy_and<
+                      __lazy_not<is_same<typename decay<_Tp>::type, __tuple_leaf>>
+                    , is_constructible<_Hp, _Tp>
+                    >::value
+                >::type
+            >
         _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
         explicit __tuple_leaf(_Tp&& __t) _NOEXCEPT_((is_nothrow_constructible<_Hp, _Tp>::value))
             : value(_VSTD::forward<_Tp>(__t))
@@ -316,7 +322,13 @@ public:
             : _Hp(__a) {}
 
     template <class _Tp,
-              class = typename enable_if<is_constructible<_Hp, _Tp>::value>::type>
+              class = typename enable_if<
+                  __lazy_and<
+                        __lazy_not<is_same<typename decay<_Tp>::type, __tuple_leaf>>
+                      , is_constructible<_Hp, _Tp>
+                    >::value
+                >::type
+            >
         _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
         explicit __tuple_leaf(_Tp&& __t) _NOEXCEPT_((is_nothrow_constructible<_Hp, _Tp>::value))
             : _Hp(_VSTD::forward<_Tp>(__t)) {}
@@ -336,6 +348,9 @@ public:
         explicit __tuple_leaf(integral_constant<int, 2>, const _Alloc& __a, _Tp&& __t)
             : _Hp(_VSTD::forward<_Tp>(__t), __a) {}
 
+    __tuple_leaf(__tuple_leaf const &) = default;
+    __tuple_leaf(__tuple_leaf &&) = default;
+
     template <class _Tp>
         _LIBCPP_INLINE_VISIBILITY
         __tuple_leaf&

Modified: libcxx/trunk/test/utilities/tuple/tuple.tuple/tuple.cnstr/const_Types.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/utilities/tuple/tuple.tuple/tuple.cnstr/const_Types.pass.cpp?rev=213888&r1=213887&r2=213888&view=diff
==============================================================================
--- libcxx/trunk/test/utilities/tuple/tuple.tuple/tuple.cnstr/const_Types.pass.cpp (original)
+++ libcxx/trunk/test/utilities/tuple/tuple.tuple/tuple.cnstr/const_Types.pass.cpp Thu Jul 24 13:48:34 2014
@@ -17,6 +17,40 @@
 #include <string>
 #include <cassert>
 
+
+template <class ...>
+struct never {
+    enum { value = 0 };
+};
+
+struct NoValueCtor
+{
+    NoValueCtor() : id(++count) {}
+    NoValueCtor(NoValueCtor const & other) : id(other.id) { ++count; }
+
+    // The constexpr is required to make is_constructible instantiate this template.
+    // The explicit is needed to test-around a similar bug with is_convertible.
+    template <class T>
+    constexpr explicit NoValueCtor(T)
+    { static_assert(never<T>::value, "This should not be instantiated"); }
+
+    static int count;
+    int id;
+};
+
+int NoValueCtor::count = 0;
+
+
+struct NoValueCtorEmpty
+{
+    NoValueCtorEmpty() {}
+    NoValueCtorEmpty(NoValueCtorEmpty const &) {}
+
+    template <class T>
+    constexpr explicit NoValueCtorEmpty(T)
+    { static_assert(never<T>::value, "This should not be instantiated"); }
+};
+
 int main()
 {
     {
@@ -56,6 +90,23 @@ int main()
         assert(std::get<1>(t) == nullptr);
         assert(std::get<2>(t) == "text");
     }
+    // __tuple_leaf<T> uses is_constructible<T, U> to disable its explicit converting
+    // constructor overload __tuple_leaf(U &&). Evaluating is_constructible can cause a compile error.
+    // This overload is evaluated when __tuple_leafs copy or move ctor is called.
+    // This checks that is_constructible is not evaluated when U == __tuple_leaf.
+    {
+        std::tuple<int, NoValueCtor, int, int> t(1, NoValueCtor(), 2, 3);
+        assert(std::get<0>(t) == 1);
+        assert(std::get<1>(t).id == 1);
+        assert(std::get<2>(t) == 2);
+        assert(std::get<3>(t) == 3);
+    }
+    {
+        std::tuple<int, NoValueCtorEmpty, int, int> t(1, NoValueCtorEmpty(), 2, 3);
+        assert(std::get<0>(t) == 1);
+        assert(std::get<2>(t) == 2);
+        assert(std::get<3>(t) == 3);
+    }
     // extensions
     {
         std::tuple<int, char*, std::string> t(2);

Modified: libcxx/trunk/test/utilities/tuple/tuple.tuple/tuple.cnstr/move.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/utilities/tuple/tuple.tuple/tuple.cnstr/move.pass.cpp?rev=213888&r1=213887&r2=213888&view=diff
==============================================================================
--- libcxx/trunk/test/utilities/tuple/tuple.tuple/tuple.cnstr/move.pass.cpp (original)
+++ libcxx/trunk/test/utilities/tuple/tuple.tuple/tuple.cnstr/move.pass.cpp Thu Jul 24 13:48:34 2014
@@ -18,6 +18,18 @@
 
 #include "../MoveOnly.h"
 
+struct ConstructsWithTupleLeaf
+{
+    ConstructsWithTupleLeaf() {}
+
+    ConstructsWithTupleLeaf(ConstructsWithTupleLeaf const &) { assert(false); }
+    ConstructsWithTupleLeaf(ConstructsWithTupleLeaf &&) {}
+
+    template <class T>
+    ConstructsWithTupleLeaf(T t)
+    { assert(false); }
+};
+
 int main()
 {
     {
@@ -46,4 +58,12 @@ int main()
         assert(std::get<1>(t) == 1);
         assert(std::get<2>(t) == 2);
     }
+    // A bug in tuple caused __tuple_leaf to use its explicit converting constructor
+    //  as its move constructor. This tests that ConstructsWithTupleLeaf is not called
+    // (w/ __tuple_leaf)
+    {
+        typedef std::tuple<ConstructsWithTupleLeaf> d_t;
+        d_t d((ConstructsWithTupleLeaf()));
+        d_t d2(static_cast<d_t &&>(d));
+    }
 }

Modified: libcxx/trunk/test/utilities/tuple/tuple.tuple/tuple.elem/tuple.by.type1.fail.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/utilities/tuple/tuple.tuple/tuple.elem/tuple.by.type1.fail.cpp?rev=213888&r1=213887&r2=213888&view=diff
==============================================================================
--- libcxx/trunk/test/utilities/tuple/tuple.tuple/tuple.elem/tuple.by.type1.fail.cpp (original)
+++ libcxx/trunk/test/utilities/tuple/tuple.tuple/tuple.elem/tuple.by.type1.fail.cpp Thu Jul 24 13:48:34 2014
@@ -18,7 +18,7 @@ int main()
 #if _LIBCPP_STD_VER > 11
     typedef std::complex<float> cf;
     auto t1 = std::make_tuple<int, std::string> ( 42, "Hi" );
-    assert ( std::get<cf>(t1) == cf {1,2} );    // no such type
+    assert (( std::get<cf>(t1) == cf {1,2} )); // no such type
 #else
 #error
 #endif

Modified: libcxx/trunk/test/utilities/utility/pairs/pair.astuple/pairs.by.type1.fail.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/utilities/utility/pairs/pair.astuple/pairs.by.type1.fail.cpp?rev=213888&r1=213887&r2=213888&view=diff
==============================================================================
--- libcxx/trunk/test/utilities/utility/pairs/pair.astuple/pairs.by.type1.fail.cpp (original)
+++ libcxx/trunk/test/utilities/utility/pairs/pair.astuple/pairs.by.type1.fail.cpp Thu Jul 24 13:48:34 2014
@@ -17,7 +17,7 @@ int main()
 #if _LIBCPP_STD_VER > 11
     typedef std::complex<float> cf;
     auto t1 = std::make_pair<int, double> ( 42, 3.4 );
-    assert ( std::get<cf>(t1) == cf {1,2} );    // no such type
+    assert (( std::get<cf>(t1) == cf {1,2} ));  // no such type
 #else
 #error
 #endif





More information about the cfe-commits mailing list