Issue |
154820
|
Summary |
clang frontend in clang 20 uses >60GB of RAM (and crashes with OOM) to compile a small template meta-program that compiles fine in clang 18 and 19
|
Labels |
clang
|
Assignees |
|
Reporter |
dwith-ts
|
Hi,
I have a condensed template meta-program below which causes clang 20.1.0 to use a large amount of memory (verified that it uses more than 60GB) and then it crashes with out-of-memory on my machine.
The program compiles without problems with clang 18 and clang 19. I used C++17 option for all compilers.
For a quick try, here is the godbolt link: https://godbolt.org/z/67vejdxMe
Code example:
`#include <tuple>
#include <cstdint>
template<typename...> struct TypeList{};
template<typename T1, typename T2> struct Pair {
using FirstType = T1;
using SecondType = T2;
};
template <typename T1, typename T2>
T2 remove_from_start;
template <typename T1, typename T2>
using RemoveFromStart = decltype(remove_from_start<T1, T2>);
template <typename T, typename... Rest1, typename... Rest2>
RemoveFromStart<TypeList<Rest1...>, TypeList<Rest2...>>
remove_from_start<TypeList<T, Rest1...>,
TypeList<T, Rest2...>>;
template <typename T>
constexpr std::int32_t size_of = -1;
template <template <class...> class L, typename... Ts>
constexpr std::int32_t size_of<L<Ts...>> = sizeof...(Ts);
template <bool>
struct CheckingArgNr;
template <typename AllRows_T, typename AllCols_T, typename... Others_T>
using CheckConstructorArgs = typename CheckingArgNr<(
sizeof...(Others_T) > 0)>::template Result<1, AllRows_T, AllCols_T, TypeList<>, AllCols_T, Others_T...>::FirstType;
template <typename RowsT, typename AllRowsT>
using IsStartOf = std::bool_constant<size_of<AllRowsT> - size_of<RemoveFromStart<RowsT, AllRowsT>> == size_of<RowsT>>;
template <bool>
struct RemoveFromStartOfOr;
template <>
struct RemoveFromStartOfOr<true> {
template <typename StartList_T, typename FullList_T, typename>
using type = RemoveFromStart<StartList_T, FullList_T>;
};
template <>
struct RemoveFromStartOfOr<false> {
template <typename, typename, typename Fallback_T>
using type = Fallback_T;
};
template <>
struct CheckingArgNr<true> {
template <typename Pair_T>
using RowList = typename Pair_T::FirstType;
template <typename Pair_T>
using ColList = typename Pair_T::SecondType;
template <std::int32_t counter_v,
typename RemainingRows_T,
typename AllCols_T,
typename CurrentRows_T,
typename RemainingCols_T,
typename CurrentPair_T,
typename... Others_T>
using NextArgumentResult = typename CheckingArgNr<(sizeof...(Others_T) > 0)>::template Result<
counter_v + 1,
typename RemoveFromStartOfOr< //
std::is_same<ColList<CurrentPair_T>,
RemainingCols_T>::value
>::template type<RowList<CurrentPair_T>,
RemainingRows_T,
RemainingRows_T>,
AllCols_T,
std::conditional_t<std::is_same<ColList<CurrentPair_T>, RemainingCols_T>::value, TypeList<>, RowList<CurrentPair_T>>,
typename RemoveFromStartOfOr<not std::is_same<ColList<CurrentPair_T>, RemainingCols_T>::value>::
template type<ColList<CurrentPair_T>, RemainingCols_T, AllCols_T>,
Others_T...>;
template <typename RemainingRows_T,
typename AllCols_T,
typename CurrentRows_T,
typename RemainingCols_T,
typename CurrentPair_T>
static constexpr bool current_argument_check =
IsStartOf<ColList<CurrentPair_T>, RemainingCols_T>::value &&
(((size_of<CurrentRows_T> == 0) && IsStartOf<RowList<CurrentPair_T>, RemainingRows_T>::value &&
std::is_same<RemainingCols_T, AllCols_T>::value) ||
std::is_same<RowList<CurrentPair_T>, CurrentRows_T>::value);
template <std::int32_t counter_v,
typename RemainingRows_T,
typename AllCols_T,
typename CurrentRows_T,
typename RemainingCols_T,
typename CurrentPair_T,
typename... Others_T>
using Result = std::conditional_t<
current_argument_check<RemainingRows_T, AllCols_T, CurrentRows_T, RemainingCols_T, CurrentPair_T>,
NextArgumentResult<counter_v,
RemainingRows_T,
AllCols_T,
CurrentRows_T,
RemainingCols_T,
CurrentPair_T,
Others_T...>,
Pair<std::false_type, std::integral_constant<std::int32_t, counter_v>>>;
};
template <>
struct CheckingArgNr<false> {
template <std::int32_t counter_v,
typename RemainingRows_T,
typename AllCols_T,
typename CurrentRows_T,
typename RemainingCols_T>
using Result = Pair<
std::bool_constant<(size_of<RemainingRows_T> == 0)>,
std::integral_constant<std::int32_t, (size_of<RemainingRows_T> == 0) ? -1 : counter_v>>;
};
struct A; struct B; struct C; struct D; struct E; struct F; struct G;
struct H; struct I; struct J;
int main() {
using RowList1 = TypeList<A, B, H, I>;
using ColList1 = TypeList<A, B, C, D, F, G>;
// this already crashes / uses a huge amount of memory with clang 20
using Result = CheckConstructorArgs<RowList1, ColList1,
Pair<A, A>, Pair<A, B>, Pair<A, C>, Pair<A, D>,
Pair<A, F>, Pair<A, G>,
Pair<B, A>, Pair<B, B>, Pair<B, C>, Pair<B, D>,
Pair<B, F>, Pair<B, G>,
Pair<H, A>, Pair<H, B>, Pair<H, C>,
Pair<H, D>,
Pair<H, F>, Pair<H, G>,
Pair<I, A>, Pair<I, B>, Pair<I, C>,
Pair<I, D>,
Pair<I, F>, Pair<I, G>
>;
// // even larger example
// using RowList2 = TypeList<A, B, H, I>;
// using ColList2 = TypeList<A, B, C, D, E, F, G, J>;
// using Result = CheckConstructorArgs<RowList2, ColList2,
// Pair<A, A>, Pair<A, B>, Pair<A, C>, Pair<A, D>, Pair<A, E>, Pair<A, F>, Pair<A, G>, Pair<A, J>, //
// Pair<B, A>, Pair<B, B>, Pair<B, C>, Pair<B, D>, Pair<B, E>, Pair<B, F>, Pair<B, G>, Pair<B, J>, //
// Pair<H, A>, Pair<H, B>, Pair<H, C>, Pair<H, D>, Pair<H, E>, Pair<H, F>, Pair<H, G>, Pair<H, J>, //
// Pair<I, A>, Pair<I, B>, Pair<I, C>, Pair<I, D>, Pair<I, E>, Pair<I, F>, Pair<I, G>, Pair<I, J>
// >;
}`
_______________________________________________
llvm-bugs mailing list
llvm-bugs@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs