Skip to content

Commit 0da6cca

Browse files
authored
[clang] fix handling of packs in TransformSubstNonTypeTemplateParmExpr (#164350)
Since this regression was never released, there are no release notes. Fixes #164330
1 parent 69d97a6 commit 0da6cca

File tree

2 files changed

+317
-4
lines changed

2 files changed

+317
-4
lines changed

clang/lib/Sema/TreeTransform.h

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16430,12 +16430,16 @@ ExprResult TreeTransform<Derived>::TransformSubstNonTypeTemplateParmExpr(
1643016430
AssociatedDecl == E->getAssociatedDecl())
1643116431
return E;
1643216432

16433-
auto getParamAndType = [Index = E->getIndex()](Decl *AssociatedDecl)
16433+
auto getParamAndType = [E](Decl *AssociatedDecl)
1643416434
-> std::tuple<NonTypeTemplateParmDecl *, QualType> {
16435-
auto [PDecl, Arg] = getReplacedTemplateParameter(AssociatedDecl, Index);
16435+
auto [PDecl, Arg] =
16436+
getReplacedTemplateParameter(AssociatedDecl, E->getIndex());
1643616437
auto *Param = cast<NonTypeTemplateParmDecl>(PDecl);
16437-
return {Param, Arg.isNull() ? Param->getType()
16438-
: Arg.getNonTypeTemplateArgumentType()};
16438+
if (Arg.isNull())
16439+
return {Param, Param->getType()};
16440+
if (UnsignedOrNone PackIndex = E->getPackIndex())
16441+
Arg = Arg.getPackAsArray()[*PackIndex];
16442+
return {Param, Arg.getNonTypeTemplateArgumentType()};
1643916443
};
1644016444

1644116445
// If the replacement expression did not change, and the parameter type
Lines changed: 309 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,309 @@
1+
// RUN: %clang_cc1 -std=c++20 -verify %s
2+
// expected-no-diagnostics
3+
4+
template <int __v> struct integral_constant {
5+
static constexpr int value = __v;
6+
};
7+
template <bool _Val> using _BoolConstant = integral_constant<_Val>;
8+
template <int, class> struct tuple_element;
9+
template <class...> class tuple;
10+
template <int _Ip, class... _Tp> struct tuple_element<_Ip, tuple<_Tp...>> {
11+
using type = __type_pack_element<_Ip, _Tp...>;
12+
};
13+
template <class> struct tuple_size;
14+
template <bool> using __enable_if_t = int;
15+
template <template <class> class _BaseType, class _Tp, _Tp _SequenceSize>
16+
using __make_integer_sequence_impl =
17+
__make_integer_seq<_BaseType, _Tp, _SequenceSize>;
18+
template <class _Tp, _Tp...> struct __integer_sequence;
19+
template <int... _Indices>
20+
using __index_sequence = __integer_sequence<int, _Indices...>;
21+
template <int _SequenceSize>
22+
using __make_index_sequence =
23+
__make_integer_sequence_impl<__integer_sequence, int, _SequenceSize>;
24+
template <class _Tp, _Tp...> struct integer_sequence {};
25+
template <int... _Ip> using index_sequence = integer_sequence<int, _Ip...>;
26+
template <class _Tp, _Tp _Ep>
27+
using make_integer_sequence =
28+
__make_integer_sequence_impl<integer_sequence, _Tp, _Ep>;
29+
template <int _Np> using make_index_sequence = make_integer_sequence<int, _Np>;
30+
enum __element_count : int;
31+
constexpr void __constexpr_memmove(char *__dest, const char *__src,
32+
__element_count __n) {
33+
__builtin_memmove(__dest, __src, __n);
34+
}
35+
template <class _Tp> using __underlying_type_t = __underlying_type(_Tp);
36+
template <class _Tp> using underlying_type_t = __underlying_type_t<_Tp>;
37+
template <class _Tp, class> using __enable_if_tuple_size_imp = _Tp;
38+
template <class _Tp>
39+
struct tuple_size<__enable_if_tuple_size_imp<
40+
const _Tp, __enable_if_t<_BoolConstant<__is_volatile(int)>::value>>>
41+
: integral_constant<tuple_size<_Tp>::value> {};
42+
template <class... _Tp>
43+
struct tuple_size<tuple<_Tp...>> : integral_constant<sizeof...(_Tp)> {};
44+
template <class _Tp> constexpr int tuple_size_v = tuple_size<_Tp>::value;
45+
template <class _T1, class _T2> struct pair {
46+
_T1 first;
47+
_T2 second;
48+
};
49+
template <class _T1> constexpr pair<_T1, char *> make_pair(_T1, char *__t2) {
50+
return pair(_T1(), __t2);
51+
}
52+
template <int, class _Hp> struct __tuple_leaf {
53+
_Hp __value_;
54+
constexpr const _Hp &get() const { return __value_; }
55+
};
56+
template <class...> struct __tuple_impl;
57+
template <int... _Indx, class... _Tp>
58+
struct __tuple_impl<__index_sequence<_Indx...>, _Tp...>
59+
: __tuple_leaf<_Indx, _Tp>... {
60+
template <class... _Args>
61+
constexpr __tuple_impl(int, _Args... __args)
62+
: __tuple_leaf<_Indx, _Tp>(__args)... {}
63+
};
64+
template <class... _Tp> struct tuple {
65+
__tuple_impl<__make_index_sequence<sizeof...(_Tp)>, _Tp...> __base_;
66+
template <class... _Up> constexpr tuple(_Up... __u) : __base_({}, __u...) {}
67+
};
68+
template <int _Ip, class... _Tp>
69+
constexpr const tuple_element<_Ip, tuple<_Tp...>>::type &
70+
get(const tuple<_Tp...> &__t) noexcept {
71+
return static_cast<const __tuple_leaf<
72+
_Ip, typename tuple_element<_Ip, tuple<_Tp...>>::type> &>(__t.__base_)
73+
.get();
74+
}
75+
template <class... _Tp> constexpr tuple<_Tp...> make_tuple(_Tp... __t) {
76+
return tuple<_Tp...>(__t...);
77+
}
78+
constexpr int __char_traits_length_checked(const char *__s) {
79+
return __builtin_strlen(__s);
80+
}
81+
struct basic_string_view {
82+
constexpr basic_string_view() {}
83+
constexpr basic_string_view(const char *__s)
84+
: __data_(__s), __size_(__char_traits_length_checked(__s)) {}
85+
constexpr const char *begin() { return __data_; }
86+
constexpr const char *end() {
87+
return __data_ + __size_;
88+
}
89+
const char *__data_;
90+
int __size_;
91+
};
92+
template <class _Algorithm>
93+
constexpr pair<const char *, char *>
94+
__copy_move_unwrap_iters(const char *__first, const char *__last,
95+
char *__out_first) {
96+
pair<const char *, const char *> __range = {__first, __last};
97+
auto __result = _Algorithm()(__range.first, __range.second, __out_first);
98+
return make_pair(__result.first, __result.second);
99+
}
100+
struct __copy_impl {
101+
constexpr pair<const char *, char *>
102+
operator()(const char *__first, const char *__last, char *__result) {
103+
const int __n(__last - __first);
104+
__constexpr_memmove(__result, __first, __element_count(__n));
105+
return make_pair(__last, __result);
106+
}
107+
};
108+
constexpr char *copy(const char *__first, const char *__last, char *__result) {
109+
return __copy_move_unwrap_iters<__copy_impl>(__first, __last, __result).second;
110+
}
111+
constexpr char *copy_n(const char *__first, int __orig_n, char *__result) {
112+
return copy(__first, __first + __orig_n, __result);
113+
}
114+
template <int _Size> struct array {
115+
basic_string_view __elems_[_Size];
116+
constexpr basic_string_view &operator[](int __n) { return __elems_[__n]; }
117+
constexpr basic_string_view operator[](int __n) const {
118+
return __elems_[__n];
119+
}
120+
};
121+
122+
template <typename> struct FieldId;
123+
124+
template <FieldId field> constexpr auto FieldIdToInnerValue() {
125+
return field.template ToInnerValue<field>();
126+
}
127+
struct FieldNameEnum {
128+
enum class type;
129+
};
130+
template <int N> using FieldName = FieldNameEnum::type;
131+
template <typename, auto> struct GetParentMessageAtIndexImpl;
132+
template <typename, auto> struct FieldInfoHelper;
133+
template <FieldId...> struct PathImpl;
134+
template <int N> struct LongPathLiteral {
135+
consteval LongPathLiteral(const char (&s)[N]) {
136+
copy_n(s, N, long_path)[N] = field_count = long_path_size = 1;
137+
}
138+
consteval basic_string_view to_string_view() const { return long_path; }
139+
char long_path[N + 1];
140+
int long_path_size;
141+
int field_count;
142+
};
143+
template <LongPathLiteral kLongPath> consteval auto get_field_components() {
144+
basic_string_view long_path(kLongPath.to_string_view());
145+
array<kLongPath.field_count> ret;
146+
for (int i = 0; i < kLongPath.field_count; ++i)
147+
ret[i] = long_path;
148+
return ret;
149+
}
150+
template <LongPathLiteral kLongPath>
151+
constexpr auto kFieldComponents = get_field_components<kLongPath>();
152+
template <LongPathLiteral kLongPath> struct LongPathHelper {
153+
template <int... I>
154+
static PathImpl<kFieldComponents<kLongPath>[I]...>
155+
PathForLongPath(index_sequence<I...>);
156+
using type =
157+
decltype(PathForLongPath(make_index_sequence<kLongPath.field_count>{}));
158+
};
159+
template <typename T> struct PathFieldId {
160+
template <typename Arg> constexpr PathFieldId(Arg &arg) : value(arg) {}
161+
T value;
162+
};
163+
template <PathFieldId...> constexpr auto PathImplHelper();
164+
165+
template <int N> using FieldName = FieldName<N>;
166+
enum class FieldNumber;
167+
template <PathFieldId... fields>
168+
constexpr auto Path = PathImplHelper<fields...>();
169+
template <typename Proto, FieldId field>
170+
using FieldInfo =
171+
FieldInfoHelper<Proto, FieldIdToInnerValue<field>()>::type;
172+
template <> struct FieldId<FieldNameEnum::type> {
173+
constexpr FieldId(basic_string_view);
174+
int size;
175+
long hash;
176+
template <auto field> static constexpr auto ToInnerValue() {
177+
return static_cast<FieldNameEnum::type>(field.hash);
178+
}
179+
};
180+
FieldId(basic_string_view) -> FieldId<FieldNameEnum::type>;
181+
template <typename Proto, FieldId field, int index>
182+
using GetParentMessageAtIndex = GetParentMessageAtIndexImpl<
183+
Proto, FieldIdToInnerValue<field>()>::type;
184+
185+
template <typename T>
186+
PathFieldId(T &t) -> PathFieldId<decltype(LongPathLiteral(t))>;
187+
template <FieldId... fields1, FieldId... fields2>
188+
constexpr PathImpl<fields1..., fields2...> *ConcatPath(PathImpl<fields1...> *,
189+
PathImpl<fields2...> *) {
190+
return nullptr;
191+
}
192+
template <LongPathLiteral long_path_literal>
193+
constexpr LongPathHelper<long_path_literal>::type *SinglePath() {
194+
return nullptr;
195+
}
196+
template <PathFieldId... fields> constexpr auto PathImplHelper() {
197+
return ConcatPath(SinglePath<fields.value>()...);
198+
}
199+
template <auto hash_prime, auto offset_bias>
200+
constexpr auto Fnv1a(basic_string_view str) {
201+
auto hash = offset_bias;
202+
for (char c : str) {
203+
hash ^= c;
204+
hash *= hash_prime;
205+
}
206+
return hash;
207+
}
208+
constexpr auto HashField(basic_string_view str) {
209+
return Fnv1a<1099511628211u, 1039346656037>(str);
210+
}
211+
template <typename FI> struct FieldInfoValueTypeAlias : FI {};
212+
template <typename Proto, auto field> struct FieldInfoHelperBase {
213+
static constexpr auto MaskFieldNameHash() {
214+
using FieldEnum = decltype(field);
215+
return FieldEnum{static_cast<underlying_type_t<FieldEnum>>(field) & 31};
216+
}
217+
using internal_type =
218+
Proto::template FieldInfoImpl<decltype(field), MaskFieldNameHash()>;
219+
};
220+
template <typename Proto, auto field> struct FieldInfoHelper {
221+
using type = FieldInfoValueTypeAlias<
222+
typename FieldInfoHelperBase<Proto, field>::internal_type>;
223+
};
224+
225+
template <auto... fields>
226+
struct FieldId<const PathImpl<fields...> *> {
227+
constexpr FieldId(PathImpl<fields...> *) : path() {}
228+
template <auto field> static constexpr auto ToInnerValue() {
229+
return field.path;
230+
}
231+
const PathImpl<fields...> *path;
232+
};
233+
template <auto... fields>
234+
FieldId(PathImpl<fields...> *)
235+
-> FieldId<const PathImpl<fields...> *>;
236+
237+
template <auto> struct UnpackedField {
238+
static constexpr bool is_path = false;
239+
};
240+
template <auto... fields, const PathImpl<fields...> *path>
241+
struct UnpackedField<path> {
242+
static constexpr auto value = make_tuple(fields...);
243+
static constexpr bool is_path = true;
244+
};
245+
template <typename Proto, FieldId... fields, const PathImpl<fields...> *path>
246+
struct GetParentMessageAtIndexImpl<Proto, path> {
247+
using type = Proto;
248+
};
249+
250+
constexpr FieldId<FieldNameEnum::type>::FieldId(basic_string_view str)
251+
: size(), hash(HashField(str)) {}
252+
template <FieldId field> constexpr bool IsPath() {
253+
return UnpackedField<
254+
FieldIdToInnerValue<field>()>::is_path;
255+
}
256+
template <FieldId field> constexpr auto UnpackFieldToTuple() {
257+
return UnpackedField<FieldIdToInnerValue<field>()>::value;
258+
}
259+
template <int> struct CompileTimeString {
260+
consteval CompileTimeString(basic_string_view &v) : internal_view_(v) {}
261+
basic_string_view &internal_view_;
262+
};
263+
CompileTimeString(basic_string_view) -> CompileTimeString<0>;
264+
265+
template <CompileTimeString... parts> struct NameJoiner {
266+
template <CompileTimeString... after>
267+
NameJoiner<parts...> operator+(NameJoiner<after...>);
268+
};
269+
template <FieldId> struct FieldNameBuilder;
270+
template <FieldId field>
271+
requires(!IsPath<field>())
272+
struct FieldNameBuilder<field> {
273+
template <typename Proto> static auto Get() {
274+
return NameJoiner<FieldInfo<Proto, field>::name>();
275+
}
276+
};
277+
template <FieldId field>
278+
requires(IsPath<field>())
279+
struct FieldNameBuilder<field> {
280+
static constexpr auto kTuple = UnpackFieldToTuple<field>();
281+
static constexpr int kTupleSize = tuple_size_v<decltype(kTuple)>;
282+
template <typename Proto, int... Is> static void Get(index_sequence<Is...>) {
283+
(FieldNameBuilder<get<Is>(
284+
kTuple)>::template Get<GetParentMessageAtIndex<Proto, field, Is>>() +
285+
...);
286+
}
287+
template <typename Proto> static void Get() {
288+
Get<Proto>(make_index_sequence<kTupleSize>());
289+
}
290+
};
291+
292+
struct T {
293+
template <typename FieldType, FieldType> struct FieldInfoImpl;
294+
};
295+
void AddPathsToFieldMask() {
296+
FieldNameBuilder<Path<"message_field", "int32_field">>::Get<T>();
297+
}
298+
template <> struct T::FieldInfoImpl<FieldNumber, FieldNumber{1}> {
299+
static basic_string_view name;
300+
};
301+
template <>
302+
struct T::FieldInfoImpl<FieldName<1>, FieldName<1>{12}>
303+
: FieldInfoImpl<FieldNumber, FieldNumber{1}> {};
304+
template <> struct T::FieldInfoImpl<FieldNumber, FieldNumber{10}> {
305+
static basic_string_view name;
306+
};
307+
template <>
308+
struct T::FieldInfoImpl<FieldName<3>, FieldName<3>{11}>
309+
: FieldInfoImpl<FieldNumber, FieldNumber{10}> {};

0 commit comments

Comments
 (0)