Skip to content

Commit 2c2d291

Browse files
authored
[concepts] Extract function template pack arguments from the current instantiation if possible (#80594)
Before the constraint substitution, we employ `getTemplateInstantiationArgs`, which in turn attempts to inspect `TemplateArgument`s from the function template. For parameter packs from their parent contexts, we used to extract the arguments from the specialization type, in which could result in non-canonical argument types e.g. `PackExpansionType`. This may break the contract that, during a tree transformation, in `TreeTransform::TryExpandParameterPacks`, the corresponding `TemplateArgument`s for an `UnexpandedParameterPack` are expected to be of `Pack` kinds if we're expanding template parameters. Fixes #72557.
1 parent 0123cef commit 2c2d291

File tree

3 files changed

+51
-2
lines changed

3 files changed

+51
-2
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,9 @@ Bug Fixes to C++ Support
197197
Fixes (`#67976 <https://github.com/llvm/llvm-project/issues/67976>`_)
198198
- Fix crash and diagnostic with const qualified member operator new.
199199
Fixes (`#79748 <https://github.com/llvm/llvm-project/issues/79748>`_)
200+
- Fixed a crash where substituting into a requires-expression that involves parameter packs
201+
during the equivalence determination of two constraint expressions.
202+
(`#72557 <https://github.com/llvm/llvm-project/issues/72557>`_)
200203
- Fix a crash when specializing an out-of-line member function with a default
201204
parameter where we did an incorrect specialization of the initialization of
202205
the default parameter.

clang/lib/Sema/SemaTemplateInstantiate.cpp

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -241,10 +241,38 @@ Response HandleFunctionTemplateDecl(const FunctionTemplateDecl *FTD,
241241

242242
while (const Type *Ty = NNS ? NNS->getAsType() : nullptr) {
243243
if (NNS->isInstantiationDependent()) {
244-
if (const auto *TSTy = Ty->getAs<TemplateSpecializationType>())
244+
if (const auto *TSTy = Ty->getAs<TemplateSpecializationType>()) {
245+
ArrayRef<TemplateArgument> Arguments = TSTy->template_arguments();
246+
// Prefer template arguments from the injected-class-type if possible.
247+
// For example,
248+
// ```cpp
249+
// template <class... Pack> struct S {
250+
// template <class T> void foo();
251+
// };
252+
// template <class... Pack> template <class T>
253+
// ^^^^^^^^^^^^^ InjectedTemplateArgs
254+
// They're of kind TemplateArgument::Pack, not of
255+
// TemplateArgument::Type.
256+
// void S<Pack...>::foo() {}
257+
// ^^^^^^^
258+
// TSTy->template_arguments() (which are of PackExpansionType)
259+
// ```
260+
// This meets the contract in
261+
// TreeTransform::TryExpandParameterPacks that the template arguments
262+
// for unexpanded parameters should be of a Pack kind.
263+
if (TSTy->isCurrentInstantiation()) {
264+
auto *RD = TSTy->getCanonicalTypeInternal()->getAsCXXRecordDecl();
265+
if (ClassTemplateDecl *CTD = RD->getDescribedClassTemplate())
266+
Arguments = CTD->getInjectedTemplateArgs();
267+
else if (auto *Specialization =
268+
dyn_cast<ClassTemplateSpecializationDecl>(RD))
269+
Arguments =
270+
Specialization->getTemplateInstantiationArgs().asArray();
271+
}
245272
Result.addOuterTemplateArguments(
246-
const_cast<FunctionTemplateDecl *>(FTD), TSTy->template_arguments(),
273+
const_cast<FunctionTemplateDecl *>(FTD), Arguments,
247274
/*Final=*/false);
275+
}
248276
}
249277

250278
NNS = NNS->getPrefix();

clang/test/SemaTemplate/concepts-out-of-line-def.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -581,3 +581,21 @@ void S<T>::test(T target, U... value)
581581
}
582582
{}
583583
} // namespace GH74447
584+
585+
namespace GH72557 {
586+
587+
template <typename...>
588+
concept IsAnyOf = true;
589+
590+
template <class... DerTs> struct DerivedCollection {
591+
template <class DerT>
592+
requires IsAnyOf<DerTs...>
593+
unsigned long index();
594+
};
595+
596+
template <class... DerTs>
597+
template <class DerT>
598+
requires IsAnyOf<DerTs...>
599+
unsigned long DerivedCollection<DerTs...>::index() {}
600+
601+
} // namespace GH72557

0 commit comments

Comments
 (0)