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

Reply via email to