Skip to content

Conversation

cor3ntin
Copy link
Contributor

@cor3ntin cor3ntin commented Oct 6, 2025

When a template parameter pack is named before
it can be substituted, it might not have a corresponding mapping.

Fixes #162125

When a template parameter pack is named before
it can be substituted, it might not have a corresponding mapping.

Fixes llvm#162125
@llvmbot llvmbot added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" labels Oct 6, 2025
@llvmbot
Copy link
Member

llvmbot commented Oct 6, 2025

@llvm/pr-subscribers-clang

Author: Corentin Jabot (cor3ntin)

Changes

When a template parameter pack is named before
it can be substituted, it might not have a corresponding mapping.

Fixes #162125


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

2 Files Affected:

  • (modified) clang/lib/Sema/SemaConcept.cpp (+2-1)
  • (modified) clang/test/SemaTemplate/concepts.cpp (+40-1)
diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index 999e302c02535..cb42d651a6586 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -277,7 +277,8 @@ class HashParameterMapping : public RecursiveASTVisitor<HashParameterMapping> {
   bool VisitTemplateTypeParmType(TemplateTypeParmType *T) {
     // A lambda expression can introduce template parameters that don't have
     // corresponding template arguments yet.
-    if (T->getDepth() >= TemplateArgs.getNumLevels())
+    if (T->getDepth() >= TemplateArgs.getNumLevels()
+        || !TemplateArgs.hasTemplateArgument(T->getDepth(), T->getIndex()))
       return true;
 
     TemplateArgument Arg = TemplateArgs(T->getDepth(), T->getIndex());
diff --git a/clang/test/SemaTemplate/concepts.cpp b/clang/test/SemaTemplate/concepts.cpp
index e5e081ffb9d0f..3671dc6ff84de 100644
--- a/clang/test/SemaTemplate/concepts.cpp
+++ b/clang/test/SemaTemplate/concepts.cpp
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -std=c++20 -ferror-limit 0 -verify %s
+// RUN: %clang_cc1 -std=c++20 -ferror-limit 0 -verify=expected,cxx20 %s
+// RUN: %clang_cc1 -std=c++2c -ferror-limit 0 -verify=expected %s
 
 namespace PR47043 {
   template<typename T> concept True = true;
@@ -1405,3 +1406,41 @@ static_assert(!std::is_constructible_v<span<4>, array<int, 3>>);
 }
 
 }
+
+
+namespace GH162125 {
+template<typename, int size>
+concept true_int = (size, true);
+
+template<typename, typename... Ts>
+concept true_types = true_int<void, sizeof...(Ts)>;
+
+template<typename, typename... Ts>
+concept true_types2 = true_int<void, Ts...[0]{1}>; // cxx20-warning {{pack indexing is a C++2c extension}}
+
+template<typename... Ts>
+struct s {
+  template<typename T> requires true_types<T, Ts...> && true_types2<T, Ts...>
+  static void f(T);
+};
+void(*test)(int) = &s<bool>::f<int>;
+}
+
+namespace GH162125_reversed {
+template<int size, typename>
+concept true_int = (size, true);
+
+template<typename, typename... Ts>
+concept true_types = true_int<sizeof...(Ts), void>;
+
+template<typename, typename... Ts>
+concept true_types2 = true_int<Ts...[0]{1}, void>;
+
+template<typename... Ts>
+struct s {
+  template<typename T> requires true_types<T, Ts...> && true_types2<T, Ts...>
+  static void f(T);
+};
+
+void(*test)(int) = &s<bool>::f<int>;
+}

Copy link

github-actions bot commented Oct 6, 2025

✅ With the latest revision this PR passed the C/C++ code formatter.

@davidstone
Copy link
Contributor

The comment for the changed condition talks about lambdas, but the failing test case doesn't use lambdas. It seems like that comment does not match the new code.

Copy link
Contributor

@zyn0217 zyn0217 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you!

Comment on lines 280 to 281
if (T->getDepth() >= TemplateArgs.getNumLevels() ||
!TemplateArgs.hasTemplateArgument(T->getDepth(), T->getIndex()))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we

Suggested change
if (T->getDepth() >= TemplateArgs.getNumLevels() ||
!TemplateArgs.hasTemplateArgument(T->getDepth(), T->getIndex()))
// There might not be a corresponding template argument before substituting into the parameter mapping, e.g. a lambda expression ...
if (!TemplateArgs.hasTemplateArgument(T->getDepth(), T->getIndex()))

?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, they are slightly different scenarios. I split the condition in 2 and added a comment, it's probably clearer that way. Thanks!

Comment on lines 1436 to 1437
template<typename, typename... Ts>
concept true_types2 = true_int<Ts...[0]{1}, void>;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
template<typename, typename... Ts>
concept true_types2 = true_int<Ts...[0]{1}, void>;
template<typename, typename... Ts>
concept true_types2 = true_int<Ts...[0]{1}, void>; // cxx20-warning {{pack indexing is a C++2c extension}}

@cor3ntin cor3ntin merged commit bc39a8f into llvm:main Oct 7, 2025
9 checks passed
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.

[clang] Assertion failure from member function of variadic class template constrained on class template parameters
4 participants