[libc++] Fix template instantiation depth issues with std::tuple

This fixes the issue by implementing _And using the short-circuiting
SFINAE trick that we previously used only in std::tuple. One thing we
could look into is use the naive recursive implementation for disjunctions
with a small number of arguments, and use that trick with larger numbers
of arguments. It might be the case that the constant overhead for setting
up the SFINAE trick makes it only worth doing for larger packs, but that's
left for further work.

This problem was raised in https://reviews.llvm.org/D96523.

Differential Revision: https://reviews.llvm.org/D101661
This commit is contained in:
Louis Dionne 2021-05-03 12:06:28 -04:00
parent 9f3f6d7bd8
commit 84f0bb6195
2 changed files with 43 additions and 6 deletions

View File

@ -476,8 +476,6 @@ struct _MetaBase<true> {
using _EnableIfImpl _LIBCPP_NODEBUG_TYPE = _Tp;
template <class _Result, class _First, class ..._Rest>
using _OrImpl _LIBCPP_NODEBUG_TYPE = typename _MetaBase<_First::value != true && sizeof...(_Rest) != 0>::template _OrImpl<_First, _Rest...>;
template <class _Result, class _First, class ..._Rest>
using _AndImpl _LIBCPP_NODEBUG_TYPE = typename _MetaBase<_First::value == true && sizeof...(_Rest) != 0>::template _AndImpl<_First, _Rest...>;
};
template <>
@ -488,8 +486,6 @@ struct _MetaBase<false> {
using _SelectApplyImpl _LIBCPP_NODEBUG_TYPE = _SecondFn<_Args...>;
template <class _Result, class ...>
using _OrImpl _LIBCPP_NODEBUG_TYPE = _Result;
template <class _Result, class ...>
using _AndImpl _LIBCPP_NODEBUG_TYPE = _Result;
};
template <bool _Cond, class _Ret = void>
using _EnableIf _LIBCPP_NODEBUG_TYPE = typename _MetaBase<_Cond>::template _EnableIfImpl<_Ret>;
@ -497,8 +493,6 @@ template <bool _Cond, class _IfRes, class _ElseRes>
using _If _LIBCPP_NODEBUG_TYPE = typename _MetaBase<_Cond>::template _SelectImpl<_IfRes, _ElseRes>;
template <class ..._Rest>
using _Or _LIBCPP_NODEBUG_TYPE = typename _MetaBase< sizeof...(_Rest) != 0 >::template _OrImpl<false_type, _Rest...>;
template <class ..._Rest>
using _And _LIBCPP_NODEBUG_TYPE = typename _MetaBase< sizeof...(_Rest) != 0 >::template _AndImpl<true_type, _Rest...>;
template <class _Pred>
struct _Not : _BoolConstant<!_Pred::value> {};
template <class ..._Args>
@ -506,6 +500,14 @@ using _FirstType _LIBCPP_NODEBUG_TYPE = typename _MetaBase<(sizeof...(_Args) >=
template <class ..._Args>
using _SecondType _LIBCPP_NODEBUG_TYPE = typename _MetaBase<(sizeof...(_Args) >= 2)>::template _SecondImpl<_Args...>;
template <class ...> using __expand_to_true = true_type;
template <class ..._Pred>
__expand_to_true<_EnableIf<_Pred::value>...> __and_helper(int);
template <class ...>
false_type __and_helper(...);
template <class ..._Pred>
using _And _LIBCPP_NODEBUG_TYPE = decltype(__and_helper<_Pred...>(0));
template <template <class...> class _Func, class ..._Args>
struct _Lazy : _Func<_Args...> {};

View File

@ -0,0 +1,35 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11
// Make sure that we don't blow up the template instantiation recursion depth
// for tuples of size <= 1024.
#include <tuple>
#include <cassert>
#include <utility>
template <size_t... I>
constexpr void CreateTuple(std::index_sequence<I...>) {
std::tuple<decltype(I)...> tuple(I...);
assert(std::get<0>(tuple) == 0);
assert(std::get<sizeof...(I)-1>(tuple) == sizeof...(I)-1);
}
constexpr bool test() {
CreateTuple(std::make_index_sequence<1024>{});
return true;
}
int main(int, char**) {
test();
static_assert(test(), "");
return 0;
}