Skip to content

Commit 84f0bb6

Browse files
committed
[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
1 parent 9f3f6d7 commit 84f0bb6

File tree

2 files changed

+43
-6
lines changed

2 files changed

+43
-6
lines changed

libcxx/include/type_traits

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -476,8 +476,6 @@ struct _MetaBase<true> {
476476
using _EnableIfImpl _LIBCPP_NODEBUG_TYPE = _Tp;
477477
template <class _Result, class _First, class ..._Rest>
478478
using _OrImpl _LIBCPP_NODEBUG_TYPE = typename _MetaBase<_First::value != true && sizeof...(_Rest) != 0>::template _OrImpl<_First, _Rest...>;
479-
template <class _Result, class _First, class ..._Rest>
480-
using _AndImpl _LIBCPP_NODEBUG_TYPE = typename _MetaBase<_First::value == true && sizeof...(_Rest) != 0>::template _AndImpl<_First, _Rest...>;
481479
};
482480

483481
template <>
@@ -488,24 +486,28 @@ struct _MetaBase<false> {
488486
using _SelectApplyImpl _LIBCPP_NODEBUG_TYPE = _SecondFn<_Args...>;
489487
template <class _Result, class ...>
490488
using _OrImpl _LIBCPP_NODEBUG_TYPE = _Result;
491-
template <class _Result, class ...>
492-
using _AndImpl _LIBCPP_NODEBUG_TYPE = _Result;
493489
};
494490
template <bool _Cond, class _Ret = void>
495491
using _EnableIf _LIBCPP_NODEBUG_TYPE = typename _MetaBase<_Cond>::template _EnableIfImpl<_Ret>;
496492
template <bool _Cond, class _IfRes, class _ElseRes>
497493
using _If _LIBCPP_NODEBUG_TYPE = typename _MetaBase<_Cond>::template _SelectImpl<_IfRes, _ElseRes>;
498494
template <class ..._Rest>
499495
using _Or _LIBCPP_NODEBUG_TYPE = typename _MetaBase< sizeof...(_Rest) != 0 >::template _OrImpl<false_type, _Rest...>;
500-
template <class ..._Rest>
501-
using _And _LIBCPP_NODEBUG_TYPE = typename _MetaBase< sizeof...(_Rest) != 0 >::template _AndImpl<true_type, _Rest...>;
502496
template <class _Pred>
503497
struct _Not : _BoolConstant<!_Pred::value> {};
504498
template <class ..._Args>
505499
using _FirstType _LIBCPP_NODEBUG_TYPE = typename _MetaBase<(sizeof...(_Args) >= 1)>::template _FirstImpl<_Args...>;
506500
template <class ..._Args>
507501
using _SecondType _LIBCPP_NODEBUG_TYPE = typename _MetaBase<(sizeof...(_Args) >= 2)>::template _SecondImpl<_Args...>;
508502

503+
template <class ...> using __expand_to_true = true_type;
504+
template <class ..._Pred>
505+
__expand_to_true<_EnableIf<_Pred::value>...> __and_helper(int);
506+
template <class ...>
507+
false_type __and_helper(...);
508+
template <class ..._Pred>
509+
using _And _LIBCPP_NODEBUG_TYPE = decltype(__and_helper<_Pred...>(0));
510+
509511
template <template <class...> class _Func, class ..._Args>
510512
struct _Lazy : _Func<_Args...> {};
511513

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// -*- C++ -*-
2+
//===----------------------------------------------------------------------===//
3+
//
4+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5+
// See https://llvm.org/LICENSE.txt for license information.
6+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7+
//
8+
//===----------------------------------------------------------------------===//
9+
10+
// UNSUPPORTED: c++03, c++11
11+
12+
// Make sure that we don't blow up the template instantiation recursion depth
13+
// for tuples of size <= 1024.
14+
15+
#include <tuple>
16+
#include <cassert>
17+
#include <utility>
18+
19+
template <size_t... I>
20+
constexpr void CreateTuple(std::index_sequence<I...>) {
21+
std::tuple<decltype(I)...> tuple(I...);
22+
assert(std::get<0>(tuple) == 0);
23+
assert(std::get<sizeof...(I)-1>(tuple) == sizeof...(I)-1);
24+
}
25+
26+
constexpr bool test() {
27+
CreateTuple(std::make_index_sequence<1024>{});
28+
return true;
29+
}
30+
31+
int main(int, char**) {
32+
test();
33+
static_assert(test(), "");
34+
return 0;
35+
}

0 commit comments

Comments
 (0)