Skip to content

[concepts] Extract function template pack arguments from the current instantiation if possible #80594

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Feb 6, 2024

Conversation

zyn0217
Copy link
Contributor

@zyn0217 zyn0217 commented Feb 4, 2024

Before the constraint substitution, we employ getTemplateInstantiationArgs, which in turn attempts to inspect TemplateArguments 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 TemplateArguments for an UnexpandedParameterPack are expected to be of Pack kinds if we're expanding template parameters.

Fixes #72557.

@zyn0217 zyn0217 changed the title [concepts] Fixes for gh72557 [concepts] Extract function template pack arguments from the current instantiation if possible Feb 4, 2024
@zyn0217 zyn0217 marked this pull request as ready for review February 4, 2024 11:22
@llvmbot llvmbot added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" labels Feb 4, 2024
@llvmbot
Copy link
Member

llvmbot commented Feb 4, 2024

@llvm/pr-subscribers-clang

Author: Younan Zhang (zyn0217)

Changes

Before the constraint substitution, we employ getTemplateInstantiationArgs, which in turn attempts to inspect TemplateArguments 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 TemplateArguments for an UnexpandedParameterPack are expected to be of Pack kinds if we're expanding template parameters.

Fixes #72557.


Full diff: https://github.com/llvm/llvm-project/pull/80594.diff

3 Files Affected:

  • (modified) clang/docs/ReleaseNotes.rst (+3)
  • (modified) clang/lib/Sema/SemaTemplateInstantiate.cpp (+30-2)
  • (modified) clang/test/SemaTemplate/concepts-out-of-line-def.cpp (+18)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 3596109bf044f..4d57ea4fd55b8 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -197,6 +197,9 @@ Bug Fixes to C++ Support
   Fixes (`#67976 <https://github.com/llvm/llvm-project/issues/67976>`_)
 - Fix crash and diagnostic with const qualified member operator new.
   Fixes (`#79748 <https://github.com/llvm/llvm-project/issues/79748>`_)
+- Fixed a crash where substituting into a requires-expression that involves parameter packs
+  during the equivalence determination of two constraint expressions.
+  (`#72557 <https://github.com/llvm/llvm-project/issues/72557>`_)
 - Fix a crash when specializing an out-of-line member function with a default
   parameter where we did an incorrect specialization of the initialization of
   the default parameter.
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index e5999fa50117e..878b557a999e1 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -241,10 +241,38 @@ Response HandleFunctionTemplateDecl(const FunctionTemplateDecl *FTD,
 
     while (const Type *Ty = NNS ? NNS->getAsType() : nullptr) {
       if (NNS->isInstantiationDependent()) {
-        if (const auto *TSTy = Ty->getAs<TemplateSpecializationType>())
+        if (const auto *TSTy = Ty->getAs<TemplateSpecializationType>()) {
+          ArrayRef<TemplateArgument> Arguments = TSTy->template_arguments();
+          // Prefer template arguments from the injected-class-type if possible.
+          // For example,
+          // ```cpp
+          // template <class... Pack> struct S {
+          //   template <class T> void foo();
+          // };
+          // template <class... Pack> template <class T>
+          //           ^^^^^^^^^^^^^ InjectedTemplateArgs
+          //           They're of kind TemplateArgument::Pack, not of
+          //           TemplateArgument::Type.
+          // void S<Pack...>::foo() {}
+          //        ^^^^^^^
+          //        TSTy->template_arguments() (which are of PackExpansionType)
+          // ```
+          // This meets the contract in
+          // TreeTransform::TryExpandParameterPacks that the template arguments
+          // for unexpanded parameters should be of a Pack kind.
+          if (TSTy->isCurrentInstantiation()) {
+            auto *RD = TSTy->getCanonicalTypeInternal()->getAsCXXRecordDecl();
+            if (ClassTemplateDecl *CTD = RD->getDescribedClassTemplate())
+              Arguments = CTD->getInjectedTemplateArgs();
+            else if (auto *Specializtion =
+                         dyn_cast<ClassTemplateSpecializationDecl>(RD))
+              Arguments =
+                  Specializtion->getTemplateInstantiationArgs().asArray();
+          }
           Result.addOuterTemplateArguments(
-              const_cast<FunctionTemplateDecl *>(FTD), TSTy->template_arguments(),
+              const_cast<FunctionTemplateDecl *>(FTD), Arguments,
               /*Final=*/false);
+        }
       }
 
       NNS = NNS->getPrefix();
diff --git a/clang/test/SemaTemplate/concepts-out-of-line-def.cpp b/clang/test/SemaTemplate/concepts-out-of-line-def.cpp
index b6fea2e0b4b31..0142efcdc3ee8 100644
--- a/clang/test/SemaTemplate/concepts-out-of-line-def.cpp
+++ b/clang/test/SemaTemplate/concepts-out-of-line-def.cpp
@@ -581,3 +581,21 @@ void S<T>::test(T target, U... value)
   }
 {}
 } // namespace GH74447
+
+namespace GH72557 {
+
+template <typename...>
+concept IsAnyOf = true;
+
+template <class... DerTs> struct DerivedCollection {
+  template <class DerT>
+    requires IsAnyOf<DerTs...>
+  unsigned long index();
+};
+
+template <class... DerTs>
+template <class DerT>
+  requires IsAnyOf<DerTs...>
+unsigned long DerivedCollection<DerTs...>::index() {}
+
+} // namespace GH72557

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Failed to match declaration to definition of requires-constrained function since clang-17
3 participants