[v3 PATCH] Protect allocator-overloads of tuple-from-tuple constructors from cases that would create dangling references.

Ville Voutilainen ville.voutilainen@gmail.com
Sat May 28 18:26:00 GMT 2016


The fix to avoid binding dangling references to temporaries for tuple's
constructors that take tuples of different type didn't include the fix
for allocator overloads. That was just lazy, and I should feel ashamed.
This patch fixes it, and takes us one step further to pass libc++'s testsuite
for tuple. The added _NonNestedTuple checks could actually be folded
into the recently-added _TMCT alias, but I'll do that as a separate cleanup
patch. For now, this should do as an easy and straightforward fix.

Tested on Linux-x64.

2016-05-28  Ville Voutilainen  <ville.voutilainen@gmail.com>

    Protect allocator-overloads of tuple-from-tuple constructors
    from cases that would create dangling references.
    * include/std/tuple (tuple(allocator_arg_t, const _Alloc&,
     const tuple<_UElements...>&), tuple(allocator_arg_t, const _Alloc&,
     tuple<_UElements...>&&)): Add a check for _NonNestedTuple.
    * testsuite/20_util/tuple/cons/nested_tuple_construct.cc: Adjust.
-------------- next part --------------
diff --git a/libstdc++-v3/include/std/tuple b/libstdc++-v3/include/std/tuple
index ea88793..17c8204 100644
--- a/libstdc++-v3/include/std/tuple
+++ b/libstdc++-v3/include/std/tuple
@@ -769,11 +769,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	tuple(allocator_arg_t __tag, const _Alloc& __a, tuple&& __in)
 	: _Inherited(__tag, __a, static_cast<_Inherited&&>(__in)) { }
 
-      template<typename _Alloc, typename... _UElements, typename
+      template<typename _Alloc, typename _Dummy = void,
+	       typename... _UElements, typename
         enable_if<_TMCT<_UElements...>::template
                     _ConstructibleTuple<_UElements...>()
                   && _TMCT<_UElements...>::template
-                    _ImplicitlyConvertibleTuple<_UElements...>(),
+                    _ImplicitlyConvertibleTuple<_UElements...>()
+                  && _TNTC<_Dummy>::template
+                    _NonNestedTuple<tuple<_UElements...>&&>(),
         bool>::type=true>
 	tuple(allocator_arg_t __tag, const _Alloc& __a,
 	      const tuple<_UElements...>& __in)
@@ -781,11 +784,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	             static_cast<const _Tuple_impl<0, _UElements...>&>(__in))
 	{ }
 
-      template<typename _Alloc, typename... _UElements, typename
+      template<typename _Alloc, typename _Dummy = void,
+	       typename... _UElements, typename
         enable_if<_TMCT<_UElements...>::template
                     _ConstructibleTuple<_UElements...>()
                   && !_TMCT<_UElements...>::template
-                    _ImplicitlyConvertibleTuple<_UElements...>(),
+                    _ImplicitlyConvertibleTuple<_UElements...>()
+                  && _TNTC<_Dummy>::template
+                    _NonNestedTuple<tuple<_UElements...>&&>(),
         bool>::type=false>
 	explicit tuple(allocator_arg_t __tag, const _Alloc& __a,
 	      const tuple<_UElements...>& __in)
@@ -793,11 +799,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	             static_cast<const _Tuple_impl<0, _UElements...>&>(__in))
 	{ }
 
-      template<typename _Alloc, typename... _UElements, typename
+      template<typename _Alloc, typename _Dummy = void,
+	       typename... _UElements, typename
         enable_if<_TMCT<_UElements...>::template
                     _MoveConstructibleTuple<_UElements...>()
                   && _TMCT<_UElements...>::template
-                    _ImplicitlyMoveConvertibleTuple<_UElements...>(),
+                    _ImplicitlyMoveConvertibleTuple<_UElements...>()
+                  && _TNTC<_Dummy>::template
+                    _NonNestedTuple<tuple<_UElements...>&&>(),
         bool>::type=true>
 	tuple(allocator_arg_t __tag, const _Alloc& __a,
 	      tuple<_UElements...>&& __in)
@@ -805,11 +814,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	             static_cast<_Tuple_impl<0, _UElements...>&&>(__in))
 	{ }
 
-      template<typename _Alloc, typename... _UElements, typename
+      template<typename _Alloc, typename _Dummy = void,
+	       typename... _UElements, typename
         enable_if<_TMCT<_UElements...>::template
                     _MoveConstructibleTuple<_UElements...>()
                   && !_TMCT<_UElements...>::template
-                    _ImplicitlyMoveConvertibleTuple<_UElements...>(),
+                    _ImplicitlyMoveConvertibleTuple<_UElements...>()
+                  && _TNTC<_Dummy>::template
+                    _NonNestedTuple<tuple<_UElements...>&&>(),
         bool>::type=false>
 	explicit tuple(allocator_arg_t __tag, const _Alloc& __a,
 	      tuple<_UElements...>&& __in)
diff --git a/libstdc++-v3/testsuite/20_util/tuple/cons/nested_tuple_construct.cc b/libstdc++-v3/testsuite/20_util/tuple/cons/nested_tuple_construct.cc
index 39a4f73..7f64239 100644
--- a/libstdc++-v3/testsuite/20_util/tuple/cons/nested_tuple_construct.cc
+++ b/libstdc++-v3/testsuite/20_util/tuple/cons/nested_tuple_construct.cc
@@ -63,6 +63,32 @@ void f3()
   std::tuple<std::tuple<X>> t3{std::move(t2)};
 }
 
+void f4()
+{
+  std::allocator<X> a;
+  X v;
+  std::tuple<X> t1{std::allocator_arg, a, v};
+  std::tuple<std::tuple<X>&&> t2{std::allocator_arg, a, std::move(t1)};
+  std::tuple<std::tuple<X>> t3{std::allocator_arg, a, std::move(t2)};
+}
+
+void f5()
+{
+  std::allocator<X> a;
+  X v;
+  std::tuple<X> t1{std::allocator_arg, a, std::move(v)};
+  std::tuple<std::tuple<X>&&> t2{std::allocator_arg, a, std::move(t1)};
+  std::tuple<std::tuple<X>> t3{std::allocator_arg, a, std::move(t2)};
+}
+
+void f6()
+{
+  std::allocator<X> a;
+  std::tuple<X> t1{std::allocator_arg, a, X{}};
+  std::tuple<std::tuple<X>&&> t2{std::allocator_arg, a, std::move(t1)};
+  std::tuple<std::tuple<X>> t3{std::allocator_arg, a, std::move(t2)};
+}
+
 int main()
 {
   f();
@@ -74,4 +100,13 @@ int main()
   f3();
   VERIFY(result == "DefMoveDtorMoveDtorDtor");
   result = "";
+  f4();
+  VERIFY(result == "DefCopyMoveDtorDtorDtor");
+  result = "";
+  f5();
+  VERIFY(result == "DefMoveMoveDtorDtorDtor");
+  result = "";
+  f6();
+  VERIFY(result == "DefMoveDtorMoveDtorDtor");
+  result = "";
 }


More information about the Libstdc++ mailing list