Skip to content

Conversation

@zyn0217
Copy link
Contributor

@zyn0217 zyn0217 commented Oct 23, 2025

We forgot to handle those in e9972de, hence the inconsistency across multiple instantiations.

This is a regression on trunk, so no release note.

Fixes #164750

We forgot to handle those in e9972de, hence the inconsistency across
multiple instantiations.
@zyn0217 zyn0217 requested a review from cor3ntin October 23, 2025 09:03
@llvmbot llvmbot added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" labels Oct 23, 2025
@llvmbot
Copy link
Member

llvmbot commented Oct 23, 2025

@llvm/pr-subscribers-clang

Author: Younan Zhang (zyn0217)

Changes

We forgot to handle those in e9972de, hence the inconsistency across multiple instantiations.

This is a regression on trunk, so no release note.

Fixes #164750


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

2 Files Affected:

  • (modified) clang/lib/Sema/SemaConcept.cpp (+22)
  • (modified) clang/test/SemaTemplate/concepts.cpp (+59)
diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index f77fca2a69e00..741f796ea630f 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -385,6 +385,28 @@ class HashParameterMapping : public RecursiveASTVisitor<HashParameterMapping> {
     return inherited::TraverseStmt(E->getReplacement());
   }
 
+  bool TraverseTemplateName(TemplateName Template) {
+    if (auto *TTP = dyn_cast_if_present<TemplateTemplateParmDecl>(
+            Template.getAsTemplateDecl());
+        TTP && TTP->getDepth() < TemplateArgs.getNumLevels()) {
+      if (!TemplateArgs.hasTemplateArgument(TTP->getDepth(),
+                                            TTP->getPosition()))
+        return true;
+
+      TemplateArgument Arg = TemplateArgs(TTP->getDepth(), TTP->getPosition());
+      if (TTP->isParameterPack() && SemaRef.ArgPackSubstIndex) {
+        assert(Arg.getKind() == TemplateArgument::Pack &&
+               "Missing argument pack");
+        Arg = SemaRef.getPackSubstitutedTemplateArgument(Arg);
+      }
+      assert(!Arg.getAsTemplate().isNull() &&
+             "Null template template argument");
+      UsedTemplateArgs.push_back(
+          SemaRef.Context.getCanonicalTemplateArgument(Arg));
+    }
+    return inherited::TraverseTemplateName(Template);
+  }
+
   void VisitConstraint(const NormalizedConstraintWithParamMapping &Constraint) {
     if (!Constraint.hasParameterMapping()) {
       for (const auto &List : TemplateArgs)
diff --git a/clang/test/SemaTemplate/concepts.cpp b/clang/test/SemaTemplate/concepts.cpp
index 5b0f3d39d9648..becf5467a1b61 100644
--- a/clang/test/SemaTemplate/concepts.cpp
+++ b/clang/test/SemaTemplate/concepts.cpp
@@ -1573,3 +1573,62 @@ namespace GH162770 {
   template<typename... Ts> auto comma = (..., Ts());
   auto b = comma<check<e{}>>;
 } // namespace GH162770
+
+namespace GH164750 {
+
+template <typename>
+struct a;
+template <typename>
+struct b;
+
+template <template <typename> typename c, typename d, typename>
+concept e = !__is_convertible_to(c<d>*, b<d>*);
+
+template <typename...>
+struct f;
+template <typename g, typename... h>
+struct f<g, h...> {
+    g i;
+};
+
+template <typename, typename>
+struct u;
+template <typename j, template <typename> typename k, typename l>
+    requires e<k, j, l>
+struct u<const k<j>*, l> {
+    u(const a<j>*);
+};
+template <typename j, template <typename> typename k, typename l>
+struct u<const k<j>*, l> {
+    u(const b<j>*);
+};
+
+template <typename>
+struct m;
+template <typename n, typename... o>
+struct m<n (*)(o...)> {
+    template <template <typename> typename j>
+    using p = j<o...>;
+};
+
+template <typename q, typename r>
+struct s {
+    template <typename... p>
+    struct D {
+        using v = f<u<r, p>...>;
+    };
+    template <typename... t>
+    s(t... p1) : x(p1...) {}
+    m<q>::template p<D>::v x;
+};
+template <typename w, typename... t>
+void fn1(w, t... p2) {
+    s<w, t...>(p2...);
+}
+int* fn2(int) { return nullptr; }
+void fn3() {
+    fn1(fn2, static_cast<const a<int>*>(nullptr));
+    fn1(fn2, static_cast<const b<int>*>(nullptr));
+}
+
+}

@zyn0217 zyn0217 enabled auto-merge (squash) October 23, 2025 09:20
@zyn0217 zyn0217 merged commit cd6e913 into llvm:main Oct 23, 2025
12 of 13 checks passed
mikolaj-pirog pushed a commit to mikolaj-pirog/llvm-project that referenced this pull request Oct 23, 2025
We forgot to handle those in e9972de, hence the inconsistency across
multiple instantiations.

This is a regression on trunk, so no release note.

Fixes llvm#164750
dvbuka pushed a commit to dvbuka/llvm-project that referenced this pull request Oct 27, 2025
We forgot to handle those in e9972de, hence the inconsistency across
multiple instantiations.

This is a regression on trunk, so no release note.

Fixes llvm#164750
Lukacma pushed a commit to Lukacma/llvm-project that referenced this pull request Oct 29, 2025
We forgot to handle those in e9972de, hence the inconsistency across
multiple instantiations.

This is a regression on trunk, so no release note.

Fixes llvm#164750
aokblast pushed a commit to aokblast/llvm-project that referenced this pull request Oct 30, 2025
We forgot to handle those in e9972de, hence the inconsistency across
multiple instantiations.

This is a regression on trunk, so no release note.

Fixes llvm#164750
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] Concepts breakage only with multiple instantiations

3 participants