https://github.com/zyn0217 updated 
https://github.com/llvm/llvm-project/pull/161994

>From db646e20fe7acb1a88205dbf0821db02d17ed08d Mon Sep 17 00:00:00 2001
From: Younan Zhang <[email protected]>
Date: Sun, 5 Oct 2025 11:56:32 +0800
Subject: [PATCH 1/2] [Clang] Fix concept paramater mapping for SizeOfPackExpr

This expression is not handled by default in RAV, so our parameter
mapping and cache mechanism don't work when it appears in a
template argument list.

There are a few other expressions, such as PackIndexingExpr and
FunctionParmPackExpr, which are also no-ops by default.
I don't have a test case for them now, so let's leave those until
complain :/

There was also a bug in updating the parameter mapping, where the
AssociatedDecl was not updated accordingly.
---
 clang/lib/Sema/SemaConcept.cpp           | 20 +++++++----------
 clang/lib/Sema/SemaTemplateDeduction.cpp |  4 ++++
 clang/test/SemaTemplate/concepts.cpp     | 28 ++++++++++++++++++++++++
 3 files changed, 40 insertions(+), 12 deletions(-)

diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index 8413090e7ebd1..0b70f61028e49 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -264,14 +264,6 @@ class HashParameterMapping : public 
RecursiveASTVisitor<HashParameterMapping> {
 
   UnsignedOrNone OuterPackSubstIndex;
 
-  TemplateArgument getPackSubstitutedTemplateArgument(TemplateArgument Arg) {
-    assert(*SemaRef.ArgPackSubstIndex < Arg.pack_size());
-    Arg = Arg.pack_begin()[*SemaRef.ArgPackSubstIndex];
-    if (Arg.isPackExpansion())
-      Arg = Arg.getPackExpansionPattern();
-    return Arg;
-  }
-
   bool shouldVisitTemplateInstantiations() const { return true; }
 
 public:
@@ -294,7 +286,7 @@ class HashParameterMapping : public 
RecursiveASTVisitor<HashParameterMapping> {
       assert(Arg.getKind() == TemplateArgument::Pack &&
              "Missing argument pack");
 
-      Arg = getPackSubstitutedTemplateArgument(Arg);
+      Arg = SemaRef.getPackSubstitutedTemplateArgument(Arg);
     }
 
     UsedTemplateArgs.push_back(
@@ -312,7 +304,7 @@ class HashParameterMapping : public 
RecursiveASTVisitor<HashParameterMapping> {
     if (NTTP->isParameterPack() && SemaRef.ArgPackSubstIndex) {
       assert(Arg.getKind() == TemplateArgument::Pack &&
              "Missing argument pack");
-      Arg = getPackSubstitutedTemplateArgument(Arg);
+      Arg = SemaRef.getPackSubstitutedTemplateArgument(Arg);
     }
 
     UsedTemplateArgs.push_back(
@@ -363,6 +355,10 @@ class HashParameterMapping : public 
RecursiveASTVisitor<HashParameterMapping> {
     return inherited::TraverseTemplateArgument(Arg);
   }
 
+  bool TraverseSizeOfPackExpr(SizeOfPackExpr *SOPE) {
+    return TraverseDecl(SOPE->getPack());
+  }
+
   void VisitConstraint(const NormalizedConstraintWithParamMapping &Constraint) 
{
     if (!Constraint.hasParameterMapping()) {
       for (const auto &List : TemplateArgs)
@@ -2083,8 +2079,8 @@ bool 
SubstituteParameterMappings::substitute(ConceptIdConstraint &CC) {
                                         /*UpdateArgsWithConversions=*/false))
     return true;
   auto TemplateArgs = *MLTAL;
-  TemplateArgs.replaceOutermostTemplateArguments(
-      TemplateArgs.getAssociatedDecl(0).first, CTAI.SugaredConverted);
+  TemplateArgs.replaceOutermostTemplateArguments(CSE->getNamedConcept(),
+                                                 CTAI.SugaredConverted);
   return SubstituteParameterMappings(SemaRef, &TemplateArgs, ArgsAsWritten,
                                      InFoldExpr)
       .substitute(CC.getNormalizedConstraint());
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp 
b/clang/lib/Sema/SemaTemplateDeduction.cpp
index 6bba505ece07d..3baa9775a49e4 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -6718,6 +6718,10 @@ struct MarkUsedTemplateParameterVisitor : 
DynamicRecursiveASTVisitor {
     }
     return true;
   }
+
+  bool TraverseSizeOfPackExpr(SizeOfPackExpr *SOPE) override {
+    return TraverseDecl(SOPE->getPack());
+  }
 };
 }
 
diff --git a/clang/test/SemaTemplate/concepts.cpp 
b/clang/test/SemaTemplate/concepts.cpp
index 6d29f8b798e73..e3b9f9d26bfaf 100644
--- a/clang/test/SemaTemplate/concepts.cpp
+++ b/clang/test/SemaTemplate/concepts.cpp
@@ -1333,4 +1333,32 @@ static_assert(__cpp17_iterator<not_move_constructible>); 
\
 // expected-note@#is_move_constructible_v {{because 
'is_move_constructible_v<parameter_mapping_regressions::case3::not_move_constructible>'
 evaluated to false}}
 }
 
+namespace case4 {
+
+template<bool b>
+concept bool_ = b;
+
+template<typename... Ts>
+concept unary = bool_<sizeof...(Ts) == 1>;
+
+static_assert(!unary<>);
+static_assert(unary<void>);
+
+}
+
+namespace case5 {
+
+template<int size>
+concept true1 = size == size;
+
+template<typename... Ts>
+concept true2 = true1<sizeof...(Ts)>;
+
+template<typename... Ts>
+concept true3 = true2<Ts...>;
+
+static_assert(true3<void>);
+
+}
+
 }

>From 2ae72e12e495fc4ec81bbb0fa309542c168de52d Mon Sep 17 00:00:00 2001
From: Younan Zhang <[email protected]>
Date: Sun, 5 Oct 2025 12:39:45 +0800
Subject: [PATCH 2/2] Handle initializer in concept cache

---
 clang/lib/Sema/SemaConcept.cpp       |  9 +++++-
 clang/test/SemaTemplate/concepts.cpp | 43 ++++++++++++++++++++++++++++
 2 files changed, 51 insertions(+), 1 deletion(-)

diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index 0b70f61028e49..11d2d5c3938c1 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -317,8 +317,11 @@ class HashParameterMapping : public 
RecursiveASTVisitor<HashParameterMapping> {
   }
 
   bool TraverseDecl(Decl *D) {
-    if (auto *VD = dyn_cast<ValueDecl>(D))
+    if (auto *VD = dyn_cast<ValueDecl>(D)) {
+      if (auto *Var = dyn_cast<VarDecl>(VD))
+        TraverseStmt(Var->getInit());
       return TraverseType(VD->getType());
+    }
 
     return inherited::TraverseDecl(D);
   }
@@ -359,6 +362,10 @@ class HashParameterMapping : public 
RecursiveASTVisitor<HashParameterMapping> {
     return TraverseDecl(SOPE->getPack());
   }
 
+  bool VisitSubstNonTypeTemplateParmExpr(SubstNonTypeTemplateParmExpr *E) {
+    return inherited::TraverseStmt(E->getReplacement());
+  }
+
   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 e3b9f9d26bfaf..e5e081ffb9d0f 100644
--- a/clang/test/SemaTemplate/concepts.cpp
+++ b/clang/test/SemaTemplate/concepts.cpp
@@ -1361,4 +1361,47 @@ static_assert(true3<void>);
 
 }
 
+namespace case6 {
+
+namespace std {
+template <int __v>
+struct integral_constant {
+  static const int value = __v;
+};
+
+template <class _Tp, class... _Args>
+constexpr bool is_constructible_v = __is_constructible(_Tp, _Args...);
+
+template <class _From, class _To>
+constexpr bool is_convertible_v = __is_convertible(_From, _To);
+
+template <class>
+struct tuple_size;
+
+template <class _Tp>
+constexpr decltype(sizeof(int)) tuple_size_v = tuple_size<_Tp>::value;
+}  // namespace std
+
+template <int N, int X>
+concept FixedExtentConstructibleFromExtent = X == N;
+
+template <int Extent>
+struct span {
+  int static constexpr extent = Extent;
+  template <typename R, int N = std::tuple_size_v<R>>
+    requires(FixedExtentConstructibleFromExtent<extent, N>)
+  span(R);
+};
+
+template <class, int>
+struct array {};
+
+template <class _Tp, decltype(sizeof(int)) _Size>
+struct std::tuple_size<array<_Tp, _Size>> : integral_constant<_Size> {};
+
+static_assert(std::is_convertible_v<array<int, 3>, span<3>>);
+static_assert(!std::is_constructible_v<span<4>, array<int, 3>>);
+
+}
+
 }

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to