https://github.com/mizvekov created 
https://github.com/llvm/llvm-project/pull/164350

Since this regression was never released, there are no release notes.

Fixes #164330

>From 21a67cb996ceb7097fae6598513f00edd50d94d9 Mon Sep 17 00:00:00 2001
From: Matheus Izvekov <[email protected]>
Date: Mon, 20 Oct 2025 22:02:01 -0300
Subject: [PATCH] [clang] fix handling of packs in
 TransformSubstNonTypeTemplateParmExpr

Since this regression was never released, there are no release notes.

Fixes #164330
---
 clang/lib/Sema/TreeTransform.h       |  12 +-
 clang/test/SemaTemplate/GH164330.cpp | 309 +++++++++++++++++++++++++++
 2 files changed, 317 insertions(+), 4 deletions(-)
 create mode 100644 clang/test/SemaTemplate/GH164330.cpp

diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 29f0c30c6534e..0c8c1d18d317e 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -16430,12 +16430,16 @@ ExprResult 
TreeTransform<Derived>::TransformSubstNonTypeTemplateParmExpr(
       AssociatedDecl == E->getAssociatedDecl())
     return E;
 
-  auto getParamAndType = [Index = E->getIndex()](Decl *AssociatedDecl)
+  auto getParamAndType = [E](Decl *AssociatedDecl)
       -> std::tuple<NonTypeTemplateParmDecl *, QualType> {
-    auto [PDecl, Arg] = getReplacedTemplateParameter(AssociatedDecl, Index);
+    auto [PDecl, Arg] =
+        getReplacedTemplateParameter(AssociatedDecl, E->getIndex());
     auto *Param = cast<NonTypeTemplateParmDecl>(PDecl);
-    return {Param, Arg.isNull() ? Param->getType()
-                                : Arg.getNonTypeTemplateArgumentType()};
+    if (Arg.isNull())
+      return {Param, Param->getType()};
+    if (UnsignedOrNone PackIndex = E->getPackIndex())
+      Arg = Arg.getPackAsArray()[*PackIndex];
+    return {Param, Arg.getNonTypeTemplateArgumentType()};
   };
 
   // If the replacement expression did not change, and the parameter type
diff --git a/clang/test/SemaTemplate/GH164330.cpp 
b/clang/test/SemaTemplate/GH164330.cpp
new file mode 100644
index 0000000000000..767420de272e6
--- /dev/null
+++ b/clang/test/SemaTemplate/GH164330.cpp
@@ -0,0 +1,309 @@
+// RUN: %clang_cc1 -std=c++20 -verify %s
+// expected-no-diagnostics
+
+template <int __v> struct integral_constant {
+  static constexpr int value = __v;
+};
+template <bool _Val> using _BoolConstant = integral_constant<_Val>;
+template <int, class> struct tuple_element;
+template <class...> class tuple;
+template <int _Ip, class... _Tp> struct tuple_element<_Ip, tuple<_Tp...>> {
+  using type = __type_pack_element<_Ip, _Tp...>;
+};
+template <class> struct tuple_size;
+template <bool> using __enable_if_t = int;
+template <template <class> class _BaseType, class _Tp, _Tp _SequenceSize>
+using __make_integer_sequence_impl =
+    __make_integer_seq<_BaseType, _Tp, _SequenceSize>;
+template <class _Tp, _Tp...> struct __integer_sequence;
+template <int... _Indices>
+using __index_sequence = __integer_sequence<int, _Indices...>;
+template <int _SequenceSize>
+using __make_index_sequence =
+    __make_integer_sequence_impl<__integer_sequence, int, _SequenceSize>;
+template <class _Tp, _Tp...> struct integer_sequence {};
+template <int... _Ip> using index_sequence = integer_sequence<int, _Ip...>;
+template <class _Tp, _Tp _Ep>
+using make_integer_sequence =
+    __make_integer_sequence_impl<integer_sequence, _Tp, _Ep>;
+template <int _Np> using make_index_sequence = make_integer_sequence<int, _Np>;
+enum __element_count : int;
+constexpr void __constexpr_memmove(char *__dest, const char *__src,
+                                   __element_count __n) {
+  __builtin_memmove(__dest, __src, __n);
+}
+template <class _Tp> using __underlying_type_t = __underlying_type(_Tp);
+template <class _Tp> using underlying_type_t = __underlying_type_t<_Tp>;
+template <class _Tp, class> using __enable_if_tuple_size_imp = _Tp;
+template <class _Tp>
+struct tuple_size<__enable_if_tuple_size_imp<
+    const _Tp, __enable_if_t<_BoolConstant<__is_volatile(int)>::value>>>
+    : integral_constant<tuple_size<_Tp>::value> {};
+template <class... _Tp>
+struct tuple_size<tuple<_Tp...>> : integral_constant<sizeof...(_Tp)> {};
+template <class _Tp> constexpr int tuple_size_v = tuple_size<_Tp>::value;
+template <class _T1, class _T2> struct pair {
+  _T1 first;
+  _T2 second;
+};
+template <class _T1> constexpr pair<_T1, char *> make_pair(_T1, char *__t2) {
+  return pair(_T1(), __t2);
+}
+template <int, class _Hp> struct __tuple_leaf {
+  _Hp __value_;
+  constexpr const _Hp &get() const { return __value_; }
+};
+template <class...> struct __tuple_impl;
+template <int... _Indx, class... _Tp>
+struct __tuple_impl<__index_sequence<_Indx...>, _Tp...>
+    : __tuple_leaf<_Indx, _Tp>... {
+  template <class... _Args>
+  constexpr __tuple_impl(int, _Args... __args)
+      : __tuple_leaf<_Indx, _Tp>(__args)... {}
+};
+template <class... _Tp> struct tuple {
+  __tuple_impl<__make_index_sequence<sizeof...(_Tp)>, _Tp...> __base_;
+  template <class... _Up> constexpr tuple(_Up... __u) : __base_({}, __u...) {}
+};
+template <int _Ip, class... _Tp>
+constexpr const tuple_element<_Ip, tuple<_Tp...>>::type &
+get(const tuple<_Tp...> &__t) noexcept {
+  return static_cast<const __tuple_leaf<
+      _Ip, typename tuple_element<_Ip, tuple<_Tp...>>::type> &>(__t.__base_)
+      .get();
+}
+template <class... _Tp> constexpr tuple<_Tp...> make_tuple(_Tp... __t) {
+  return tuple<_Tp...>(__t...);
+}
+constexpr int __char_traits_length_checked(const char *__s) {
+  return __builtin_strlen(__s);
+}
+struct basic_string_view {
+  constexpr basic_string_view() {}
+  constexpr basic_string_view(const char *__s)
+      : __data_(__s), __size_(__char_traits_length_checked(__s)) {}
+  constexpr const char *begin() { return __data_; }
+  constexpr const char *end() {
+    return __data_ + __size_;
+  }
+  const char *__data_;
+  int __size_;
+};
+template <class _Algorithm>
+constexpr pair<const char *, char *>
+__copy_move_unwrap_iters(const char *__first, const char *__last,
+                         char *__out_first) {
+  pair<const char *, const char *> __range = {__first, __last};
+  auto __result = _Algorithm()(__range.first, __range.second, __out_first);
+  return make_pair(__result.first, __result.second);
+}
+struct __copy_impl {
+  constexpr pair<const char *, char *>
+  operator()(const char *__first, const char *__last, char *__result) {
+    const int __n(__last - __first);
+    __constexpr_memmove(__result, __first, __element_count(__n));
+    return make_pair(__last, __result);
+  }
+};
+constexpr char *copy(const char *__first, const char *__last, char *__result) {
+  return __copy_move_unwrap_iters<__copy_impl>(__first, __last, 
__result).second;
+}
+constexpr char *copy_n(const char *__first, int __orig_n, char *__result) {
+  return copy(__first, __first + __orig_n, __result);
+}
+template <int _Size> struct array {
+  basic_string_view __elems_[_Size];
+  constexpr basic_string_view &operator[](int __n) { return __elems_[__n]; }
+  constexpr basic_string_view operator[](int __n) const {
+    return __elems_[__n];
+  }
+};
+
+template <typename> struct FieldId;
+
+template <FieldId field> constexpr auto FieldIdToInnerValue() {
+  return field.template ToInnerValue<field>();
+}
+struct FieldNameEnum {
+  enum class type;
+};
+template <int N> using FieldName = FieldNameEnum::type;
+template <typename, auto> struct GetParentMessageAtIndexImpl;
+template <typename, auto> struct FieldInfoHelper;
+template <FieldId...> struct PathImpl;
+template <int N> struct LongPathLiteral {
+  consteval LongPathLiteral(const char (&s)[N]) {
+    copy_n(s, N, long_path)[N] = field_count = long_path_size = 1;
+  }
+  consteval basic_string_view to_string_view() const { return long_path; }
+  char long_path[N + 1];
+  int long_path_size;
+  int field_count;
+};
+template <LongPathLiteral kLongPath> consteval auto get_field_components() {
+  basic_string_view long_path(kLongPath.to_string_view());
+  array<kLongPath.field_count> ret;
+  for (int i = 0; i < kLongPath.field_count; ++i)
+    ret[i] = long_path;
+  return ret;
+}
+template <LongPathLiteral kLongPath>
+constexpr auto kFieldComponents = get_field_components<kLongPath>();
+template <LongPathLiteral kLongPath> struct LongPathHelper {
+  template <int... I>
+  static PathImpl<kFieldComponents<kLongPath>[I]...>
+      PathForLongPath(index_sequence<I...>);
+  using type =
+      decltype(PathForLongPath(make_index_sequence<kLongPath.field_count>{}));
+};
+template <typename T> struct PathFieldId {
+  template <typename Arg> constexpr PathFieldId(Arg &arg) : value(arg) {}
+  T value;
+};
+template <PathFieldId...> constexpr auto PathImplHelper();
+
+template <int N> using FieldName = FieldName<N>;
+enum class FieldNumber;
+template <PathFieldId... fields>
+constexpr auto Path = PathImplHelper<fields...>();
+template <typename Proto, FieldId field>
+using FieldInfo =
+    FieldInfoHelper<Proto, FieldIdToInnerValue<field>()>::type;
+template <> struct FieldId<FieldNameEnum::type> {
+  constexpr FieldId(basic_string_view);
+  int size;
+  long hash;
+  template <auto field> static constexpr auto ToInnerValue() {
+    return static_cast<FieldNameEnum::type>(field.hash);
+  }
+};
+FieldId(basic_string_view) -> FieldId<FieldNameEnum::type>;
+template <typename Proto, FieldId field, int index>
+using GetParentMessageAtIndex = GetParentMessageAtIndexImpl<
+    Proto, FieldIdToInnerValue<field>()>::type;
+
+template <typename T>
+PathFieldId(T &t) -> PathFieldId<decltype(LongPathLiteral(t))>;
+template <FieldId... fields1, FieldId... fields2>
+constexpr PathImpl<fields1..., fields2...> *ConcatPath(PathImpl<fields1...> *,
+                                                       PathImpl<fields2...> *) 
{
+  return nullptr;
+}
+template <LongPathLiteral long_path_literal>
+constexpr LongPathHelper<long_path_literal>::type *SinglePath() {
+  return nullptr;
+}
+template <PathFieldId... fields> constexpr auto PathImplHelper() {
+  return ConcatPath(SinglePath<fields.value>()...);
+}
+template <auto hash_prime, auto offset_bias>
+constexpr auto Fnv1a(basic_string_view str) {
+  auto hash = offset_bias;
+  for (char c : str) {
+    hash ^= c;
+    hash *= hash_prime;
+  }
+  return hash;
+}
+constexpr auto HashField(basic_string_view str) {
+  return Fnv1a<1099511628211u, 1039346656037>(str);
+}
+template <typename FI> struct FieldInfoValueTypeAlias : FI {};
+template <typename Proto, auto field> struct FieldInfoHelperBase {
+  static constexpr auto MaskFieldNameHash() {
+    using FieldEnum = decltype(field);
+    return FieldEnum{static_cast<underlying_type_t<FieldEnum>>(field) & 31};
+  }
+  using internal_type =
+      Proto::template FieldInfoImpl<decltype(field), MaskFieldNameHash()>;
+};
+template <typename Proto, auto field> struct FieldInfoHelper {
+  using type = FieldInfoValueTypeAlias<
+      typename FieldInfoHelperBase<Proto, field>::internal_type>;
+};
+
+template <auto... fields>
+struct FieldId<const PathImpl<fields...> *> {
+  constexpr FieldId(PathImpl<fields...> *) : path() {}
+  template <auto field> static constexpr auto ToInnerValue() {
+    return field.path;
+  }
+  const PathImpl<fields...> *path;
+};
+template <auto... fields>
+FieldId(PathImpl<fields...> *)
+    -> FieldId<const PathImpl<fields...> *>;
+
+template <auto> struct UnpackedField {
+  static constexpr bool is_path = false;
+};
+template <auto... fields, const PathImpl<fields...> *path>
+struct UnpackedField<path> {
+  static constexpr auto value = make_tuple(fields...);
+  static constexpr bool is_path = true;
+};
+template <typename Proto, FieldId... fields, const PathImpl<fields...> *path>
+struct GetParentMessageAtIndexImpl<Proto, path> {
+  using type = Proto;
+};
+
+constexpr FieldId<FieldNameEnum::type>::FieldId(basic_string_view str)
+    : size(), hash(HashField(str)) {}
+template <FieldId field> constexpr bool IsPath() {
+  return UnpackedField<
+      FieldIdToInnerValue<field>()>::is_path;
+}
+template <FieldId field> constexpr auto UnpackFieldToTuple() {
+  return UnpackedField<FieldIdToInnerValue<field>()>::value;
+}
+template <int> struct CompileTimeString {
+  consteval CompileTimeString(basic_string_view &v) : internal_view_(v) {}
+  basic_string_view &internal_view_;
+};
+CompileTimeString(basic_string_view) -> CompileTimeString<0>;
+
+template <CompileTimeString... parts> struct NameJoiner {
+  template <CompileTimeString... after>
+  NameJoiner<parts...> operator+(NameJoiner<after...>);
+};
+template <FieldId> struct FieldNameBuilder;
+template <FieldId field>
+  requires(!IsPath<field>())
+struct FieldNameBuilder<field> {
+  template <typename Proto> static auto Get() {
+    return NameJoiner<FieldInfo<Proto, field>::name>();
+  }
+};
+template <FieldId field>
+  requires(IsPath<field>())
+struct FieldNameBuilder<field> {
+  static constexpr auto kTuple = UnpackFieldToTuple<field>();
+  static constexpr int kTupleSize = tuple_size_v<decltype(kTuple)>;
+  template <typename Proto, int... Is> static void Get(index_sequence<Is...>) {
+    (FieldNameBuilder<get<Is>(
+         kTuple)>::template Get<GetParentMessageAtIndex<Proto, field, Is>>() +
+     ...);
+  }
+  template <typename Proto> static void Get() {
+    Get<Proto>(make_index_sequence<kTupleSize>());
+  }
+};
+
+struct T {
+  template <typename FieldType, FieldType> struct FieldInfoImpl;
+};
+void AddPathsToFieldMask() {
+  FieldNameBuilder<Path<"message_field", "int32_field">>::Get<T>();
+}
+template <> struct T::FieldInfoImpl<FieldNumber, FieldNumber{1}> {
+  static basic_string_view name;
+};
+template <>
+struct T::FieldInfoImpl<FieldName<1>, FieldName<1>{12}>
+    : FieldInfoImpl<FieldNumber, FieldNumber{1}> {};
+template <> struct T::FieldInfoImpl<FieldNumber, FieldNumber{10}> {
+  static basic_string_view name;
+};
+template <>
+struct T::FieldInfoImpl<FieldName<3>, FieldName<3>{11}>
+    : FieldInfoImpl<FieldNumber, FieldNumber{10}> {};

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to