[libcxx] r220769 - [libcxx] Delay evaluation of __make_tuple_types to prevent blowing the max template instantiation depth. Fixes Bug #18345

Eric Fiselier eric at efcs.ca
Mon Oct 27 23:31:22 PDT 2014


Author: ericwf
Date: Tue Oct 28 01:31:22 2014
New Revision: 220769

URL: http://llvm.org/viewvc/llvm-project?rev=220769&view=rev
Log:
[libcxx] Delay evaluation of __make_tuple_types to prevent blowing the max template instantiation depth. Fixes Bug #18345

Summary:
http://llvm.org/bugs/show_bug.cgi?id=18345

Tuple's constructor and assignment operators for "tuple-like" types evaluates __make_tuple_types unnecessarily. In the case of a large array this can blow the template instantiation depth.

Ex:
```
#include <array>
#include <tuple>
#include <memory>
 
typedef std::array<int, 1256> array_t;
typedef std::tuple<array_t> tuple_t;

int main() {
  array_t a;
  tuple_t t(a); // broken
  t = a; // broken

  // make_shared uses tuple behind the scenes. This bug breaks this code.
  std::make_shared<array_t>(a);
}
```

To prevent this from happening we delay the instantiation of `__make_tuple_types` until after we perform the length check. Currently `__make_tuple_types` is instantiated at the same time that the length check .


Test Plan: Two tests have been added. One for the "tuple-like" constructors and another for the "tuple-like" assignment operator. 

Reviewers: mclow.lists, EricWF

Reviewed By: EricWF

Subscribers: K-ballo, cfe-commits

Differential Revision: http://reviews.llvm.org/D4467

Added:
    libcxx/trunk/test/utilities/tuple/tuple.tuple/tuple.assign/tuple_array_template_depth.pass.cpp
    libcxx/trunk/test/utilities/tuple/tuple.tuple/tuple.cnstr/tuple_array_template_depth.pass.cpp
Modified:
    libcxx/trunk/include/__tuple

Modified: libcxx/trunk/include/__tuple
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/__tuple?rev=220769&r1=220768&r2=220769&view=diff
==============================================================================
--- libcxx/trunk/include/__tuple (original)
+++ libcxx/trunk/include/__tuple Tue Oct 28 01:31:22 2014
@@ -245,19 +245,30 @@ struct __make_tuple_types
 
 // __tuple_convertible
 
-template <bool, class _Tp, class _Up>
+template <class, class>
 struct __tuple_convertible_imp : public false_type {};
 
 template <class _Tp0, class ..._Tp, class _Up0, class ..._Up>
-struct __tuple_convertible_imp<true, __tuple_types<_Tp0, _Tp...>, __tuple_types<_Up0, _Up...> >
+struct __tuple_convertible_imp<__tuple_types<_Tp0, _Tp...>, __tuple_types<_Up0, _Up...> >
     : public integral_constant<bool,
                                is_convertible<_Tp0, _Up0>::value &&
-                               __tuple_convertible_imp<true, __tuple_types<_Tp...>, __tuple_types<_Up...> >::value> {};
+                               __tuple_convertible_imp<__tuple_types<_Tp...>, __tuple_types<_Up...> >::value> {};
 
 template <>
-struct __tuple_convertible_imp<true, __tuple_types<>, __tuple_types<> >
+struct __tuple_convertible_imp<__tuple_types<>, __tuple_types<> >
     : public true_type {};
 
+template <bool, class, class>
+struct __tuple_convertible_apply : public false_type {};
+
+template <class _Tp, class _Up>
+struct __tuple_convertible_apply<true, _Tp, _Up>
+  : public __tuple_convertible_imp<
+      typename __make_tuple_types<_Tp>::type
+    , typename __make_tuple_types<_Up>::type
+    >
+{};
+
 template <class _Tp, class _Up, bool = __tuple_like<typename remove_reference<_Tp>::type>::value,
                                 bool = __tuple_like<_Up>::value>
 struct __tuple_convertible
@@ -265,26 +276,36 @@ struct __tuple_convertible
 
 template <class _Tp, class _Up>
 struct __tuple_convertible<_Tp, _Up, true, true>
-    : public __tuple_convertible_imp<tuple_size<typename remove_reference<_Tp>::type>::value ==
-                                     tuple_size<_Up>::value,
-             typename __make_tuple_types<_Tp>::type, typename __make_tuple_types<_Up>::type>
+    : public __tuple_convertible_apply<tuple_size<typename remove_reference<_Tp>::type>::value ==
+                                     tuple_size<_Up>::value, _Tp, _Up>
 {};
 
 // __tuple_constructible
 
-template <bool, class _Tp, class _Up>
+template <class, class>
 struct __tuple_constructible_imp : public false_type {};
 
 template <class _Tp0, class ..._Tp, class _Up0, class ..._Up>
-struct __tuple_constructible_imp<true, __tuple_types<_Tp0, _Tp...>, __tuple_types<_Up0, _Up...> >
+struct __tuple_constructible_imp<__tuple_types<_Tp0, _Tp...>, __tuple_types<_Up0, _Up...> >
     : public integral_constant<bool,
                                is_constructible<_Up0, _Tp0>::value &&
-                               __tuple_constructible_imp<true, __tuple_types<_Tp...>, __tuple_types<_Up...> >::value> {};
+                               __tuple_constructible_imp<__tuple_types<_Tp...>, __tuple_types<_Up...> >::value> {};
 
 template <>
-struct __tuple_constructible_imp<true, __tuple_types<>, __tuple_types<> >
+struct __tuple_constructible_imp<__tuple_types<>, __tuple_types<> >
     : public true_type {};
 
+template <bool _SameSize, class, class>
+struct __tuple_constructible_apply : public false_type {};
+
+template <class _Tp, class _Up>
+struct __tuple_constructible_apply<true, _Tp, _Up>
+  : public __tuple_constructible_imp<
+      typename __make_tuple_types<_Tp>::type
+    , typename __make_tuple_types<_Up>::type
+    >
+{};
+
 template <class _Tp, class _Up, bool = __tuple_like<typename remove_reference<_Tp>::type>::value,
                                 bool = __tuple_like<_Up>::value>
 struct __tuple_constructible
@@ -292,26 +313,36 @@ struct __tuple_constructible
 
 template <class _Tp, class _Up>
 struct __tuple_constructible<_Tp, _Up, true, true>
-    : public __tuple_constructible_imp<tuple_size<typename remove_reference<_Tp>::type>::value ==
-                                     tuple_size<_Up>::value,
-             typename __make_tuple_types<_Tp>::type, typename __make_tuple_types<_Up>::type>
+    : public __tuple_constructible_apply<tuple_size<typename remove_reference<_Tp>::type>::value ==
+                                     tuple_size<_Up>::value, _Tp, _Up>
 {};
 
 // __tuple_assignable
 
-template <bool, class _Tp, class _Up>
+template <class, class>
 struct __tuple_assignable_imp : public false_type {};
 
 template <class _Tp0, class ..._Tp, class _Up0, class ..._Up>
-struct __tuple_assignable_imp<true, __tuple_types<_Tp0, _Tp...>, __tuple_types<_Up0, _Up...> >
+struct __tuple_assignable_imp<__tuple_types<_Tp0, _Tp...>, __tuple_types<_Up0, _Up...> >
     : public integral_constant<bool,
                                is_assignable<_Up0&, _Tp0>::value &&
-                               __tuple_assignable_imp<true, __tuple_types<_Tp...>, __tuple_types<_Up...> >::value> {};
+                               __tuple_assignable_imp<__tuple_types<_Tp...>, __tuple_types<_Up...> >::value> {};
 
 template <>
-struct __tuple_assignable_imp<true, __tuple_types<>, __tuple_types<> >
+struct __tuple_assignable_imp<__tuple_types<>, __tuple_types<> >
     : public true_type {};
 
+template <bool, class, class>
+struct __tuple_assignable_apply : public false_type {};
+
+template <class _Tp, class _Up>
+struct __tuple_assignable_apply<true, _Tp, _Up>
+  : __tuple_assignable_imp<
+      typename __make_tuple_types<_Tp>::type
+    , typename __make_tuple_types<_Up>::type
+    >
+{};
+
 template <class _Tp, class _Up, bool = __tuple_like<typename remove_reference<_Tp>::type>::value,
                                 bool = __tuple_like<_Up>::value>
 struct __tuple_assignable
@@ -319,9 +350,8 @@ struct __tuple_assignable
 
 template <class _Tp, class _Up>
 struct __tuple_assignable<_Tp, _Up, true, true>
-    : public __tuple_assignable_imp<tuple_size<typename remove_reference<_Tp>::type>::value ==
-                                    tuple_size<_Up>::value,
-             typename __make_tuple_types<_Tp>::type, typename __make_tuple_types<_Up>::type>
+    : public __tuple_assignable_apply<tuple_size<typename remove_reference<_Tp>::type>::value ==
+                                    tuple_size<_Up>::value, _Tp, _Up>
 {};
 
 _LIBCPP_END_NAMESPACE_STD

Added: libcxx/trunk/test/utilities/tuple/tuple.tuple/tuple.assign/tuple_array_template_depth.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/utilities/tuple/tuple.tuple/tuple.assign/tuple_array_template_depth.pass.cpp?rev=220769&view=auto
==============================================================================
--- libcxx/trunk/test/utilities/tuple/tuple.tuple/tuple.assign/tuple_array_template_depth.pass.cpp (added)
+++ libcxx/trunk/test/utilities/tuple/tuple.tuple/tuple.assign/tuple_array_template_depth.pass.cpp Tue Oct 28 01:31:22 2014
@@ -0,0 +1,32 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// <tuple>
+
+// template <class... Types> class tuple;
+
+// template <class Tuple, __tuple_assignable<Tuple, tuple> >
+//   tuple & operator=(Tuple &&);
+
+// This test checks that we do not evaluate __make_tuple_types
+// on the array when it doesn't match the size of the tuple.
+
+#include <array>
+#include <tuple>
+
+// Use 1256 to try and blow the template instantiation depth for all compilers.
+typedef std::array<char, 1256> array_t;
+typedef std::tuple<array_t> tuple_t;
+
+int main()
+{
+    array_t arr;
+    tuple_t tup;
+    tup = arr;
+}

Added: libcxx/trunk/test/utilities/tuple/tuple.tuple/tuple.cnstr/tuple_array_template_depth.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/utilities/tuple/tuple.tuple/tuple.cnstr/tuple_array_template_depth.pass.cpp?rev=220769&view=auto
==============================================================================
--- libcxx/trunk/test/utilities/tuple/tuple.tuple/tuple.cnstr/tuple_array_template_depth.pass.cpp (added)
+++ libcxx/trunk/test/utilities/tuple/tuple.tuple/tuple.cnstr/tuple_array_template_depth.pass.cpp Tue Oct 28 01:31:22 2014
@@ -0,0 +1,34 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// <tuple>
+
+// template <class... Types> class tuple;
+
+// template <class Tuple, __tuple_convertible<Tuple, tuple> >
+//   tuple(Tuple &&);
+//
+// template <class Tuple, __tuple_constructible<Tuple, tuple> >
+//   tuple(Tuple &&);
+
+// This test checks that we do not evaluate __make_tuple_types
+// on the array.
+
+#include <array>
+#include <tuple>
+
+// Use 1256 to try and blow the template instantiation depth for all compilers.
+typedef std::array<char, 1256> array_t;
+typedef std::tuple<array_t> tuple_t;
+
+int main()
+{
+    array_t arr;
+    tuple_t tup(arr);
+}





More information about the cfe-commits mailing list