From 295bce1130906e415534b8aa9104b75cb553d173 Mon Sep 17 00:00:00 2001 From: Eric Fiselier Date: Tue, 28 Oct 2014 06:31:22 +0000 Subject: [PATCH] [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 #include #include typedef std::array array_t; typedef std::tuple 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(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 llvm-svn: 220769 --- libcxx/include/__tuple | 72 +++++++++++++++------- .../tuple_array_template_depth.pass.cpp | 32 ++++++++++ .../tuple_array_template_depth.pass.cpp | 34 ++++++++++ 3 files changed, 117 insertions(+), 21 deletions(-) create mode 100644 libcxx/test/utilities/tuple/tuple.tuple/tuple.assign/tuple_array_template_depth.pass.cpp create mode 100644 libcxx/test/utilities/tuple/tuple.tuple/tuple.cnstr/tuple_array_template_depth.pass.cpp diff --git a/libcxx/include/__tuple b/libcxx/include/__tuple index ee5b916..bffb95c 100644 --- a/libcxx/include/__tuple +++ b/libcxx/include/__tuple @@ -245,19 +245,30 @@ struct __make_tuple_types // __tuple_convertible -template +template struct __tuple_convertible_imp : public false_type {}; template -struct __tuple_convertible_imp, __tuple_types<_Up0, _Up...> > +struct __tuple_convertible_imp<__tuple_types<_Tp0, _Tp...>, __tuple_types<_Up0, _Up...> > : public integral_constant::value && - __tuple_convertible_imp, __tuple_types<_Up...> >::value> {}; + __tuple_convertible_imp<__tuple_types<_Tp...>, __tuple_types<_Up...> >::value> {}; template <> -struct __tuple_convertible_imp, __tuple_types<> > +struct __tuple_convertible_imp<__tuple_types<>, __tuple_types<> > : public true_type {}; +template +struct __tuple_convertible_apply : public false_type {}; + +template +struct __tuple_convertible_apply + : public __tuple_convertible_imp< + typename __make_tuple_types<_Tp>::type + , typename __make_tuple_types<_Up>::type + > +{}; + template ::type>::value, bool = __tuple_like<_Up>::value> struct __tuple_convertible @@ -265,26 +276,36 @@ struct __tuple_convertible template struct __tuple_convertible<_Tp, _Up, true, true> - : public __tuple_convertible_imp::type>::value == - tuple_size<_Up>::value, - typename __make_tuple_types<_Tp>::type, typename __make_tuple_types<_Up>::type> + : public __tuple_convertible_apply::type>::value == + tuple_size<_Up>::value, _Tp, _Up> {}; // __tuple_constructible -template +template struct __tuple_constructible_imp : public false_type {}; template -struct __tuple_constructible_imp, __tuple_types<_Up0, _Up...> > +struct __tuple_constructible_imp<__tuple_types<_Tp0, _Tp...>, __tuple_types<_Up0, _Up...> > : public integral_constant::value && - __tuple_constructible_imp, __tuple_types<_Up...> >::value> {}; + __tuple_constructible_imp<__tuple_types<_Tp...>, __tuple_types<_Up...> >::value> {}; template <> -struct __tuple_constructible_imp, __tuple_types<> > +struct __tuple_constructible_imp<__tuple_types<>, __tuple_types<> > : public true_type {}; +template +struct __tuple_constructible_apply : public false_type {}; + +template +struct __tuple_constructible_apply + : public __tuple_constructible_imp< + typename __make_tuple_types<_Tp>::type + , typename __make_tuple_types<_Up>::type + > +{}; + template ::type>::value, bool = __tuple_like<_Up>::value> struct __tuple_constructible @@ -292,26 +313,36 @@ struct __tuple_constructible template struct __tuple_constructible<_Tp, _Up, true, true> - : public __tuple_constructible_imp::type>::value == - tuple_size<_Up>::value, - typename __make_tuple_types<_Tp>::type, typename __make_tuple_types<_Up>::type> + : public __tuple_constructible_apply::type>::value == + tuple_size<_Up>::value, _Tp, _Up> {}; // __tuple_assignable -template +template struct __tuple_assignable_imp : public false_type {}; template -struct __tuple_assignable_imp, __tuple_types<_Up0, _Up...> > +struct __tuple_assignable_imp<__tuple_types<_Tp0, _Tp...>, __tuple_types<_Up0, _Up...> > : public integral_constant::value && - __tuple_assignable_imp, __tuple_types<_Up...> >::value> {}; + __tuple_assignable_imp<__tuple_types<_Tp...>, __tuple_types<_Up...> >::value> {}; template <> -struct __tuple_assignable_imp, __tuple_types<> > +struct __tuple_assignable_imp<__tuple_types<>, __tuple_types<> > : public true_type {}; +template +struct __tuple_assignable_apply : public false_type {}; + +template +struct __tuple_assignable_apply + : __tuple_assignable_imp< + typename __make_tuple_types<_Tp>::type + , typename __make_tuple_types<_Up>::type + > +{}; + template ::type>::value, bool = __tuple_like<_Up>::value> struct __tuple_assignable @@ -319,9 +350,8 @@ struct __tuple_assignable template struct __tuple_assignable<_Tp, _Up, true, true> - : public __tuple_assignable_imp::type>::value == - tuple_size<_Up>::value, - typename __make_tuple_types<_Tp>::type, typename __make_tuple_types<_Up>::type> + : public __tuple_assignable_apply::type>::value == + tuple_size<_Up>::value, _Tp, _Up> {}; _LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/test/utilities/tuple/tuple.tuple/tuple.assign/tuple_array_template_depth.pass.cpp b/libcxx/test/utilities/tuple/tuple.tuple/tuple.assign/tuple_array_template_depth.pass.cpp new file mode 100644 index 0000000..f62d2fe --- /dev/null +++ b/libcxx/test/utilities/tuple/tuple.tuple/tuple.assign/tuple_array_template_depth.pass.cpp @@ -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. +// +//===----------------------------------------------------------------------===// + +// + +// template class tuple; + +// template > +// 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 +#include + +// Use 1256 to try and blow the template instantiation depth for all compilers. +typedef std::array array_t; +typedef std::tuple tuple_t; + +int main() +{ + array_t arr; + tuple_t tup; + tup = arr; +} diff --git a/libcxx/test/utilities/tuple/tuple.tuple/tuple.cnstr/tuple_array_template_depth.pass.cpp b/libcxx/test/utilities/tuple/tuple.tuple/tuple.cnstr/tuple_array_template_depth.pass.cpp new file mode 100644 index 0000000..65a1c70 --- /dev/null +++ b/libcxx/test/utilities/tuple/tuple.tuple/tuple.cnstr/tuple_array_template_depth.pass.cpp @@ -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. +// +//===----------------------------------------------------------------------===// + +// + +// template class tuple; + +// template > +// tuple(Tuple &&); +// +// template > +// tuple(Tuple &&); + +// This test checks that we do not evaluate __make_tuple_types +// on the array. + +#include +#include + +// Use 1256 to try and blow the template instantiation depth for all compilers. +typedef std::array array_t; +typedef std::tuple tuple_t; + +int main() +{ + array_t arr; + tuple_t tup(arr); +} -- 2.7.4