[clang] [Clang][Concepts] Normalize SizeOfPackExpr's pack declaration (PR #110238)

Younan Zhang via cfe-commits cfe-commits at lists.llvm.org
Sat Sep 28 08:11:07 PDT 2024


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

>From 23a765ac6d8e455121346405332d2066dcc0861e Mon Sep 17 00:00:00 2001
From: Younan Zhang <zyn7109 at gmail.com>
Date: Fri, 27 Sep 2024 18:23:47 +0800
Subject: [PATCH 1/7] [Clang] GH93099

---
 clang/include/clang/Sema/Sema.h               |  4 ++-
 clang/lib/Sema/SemaTemplateVariadic.cpp       | 20 +++++++----
 clang/lib/Sema/TreeTransform.h                | 16 ++++++---
 .../SemaTemplate/concepts-out-of-line-def.cpp | 34 +++++++++++++++++++
 4 files changed, 61 insertions(+), 13 deletions(-)

diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index e1c3a99cfa167e..1fce74880026ce 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -14264,7 +14264,9 @@ class Sema final : public SemaBase {
   ///
   /// This is intended for use when transforming 'sizeof...(Arg)' in order to
   /// avoid actually expanding the pack where possible.
-  std::optional<unsigned> getFullyPackExpandedSize(TemplateArgument Arg);
+  std::optional<unsigned>
+  getFullyPackExpandedSize(TemplateArgument Arg,
+                           const NamedDecl *&ParameterPack);
 
   /// Called when an expression computing the size of a parameter pack
   /// is parsed.
diff --git a/clang/lib/Sema/SemaTemplateVariadic.cpp b/clang/lib/Sema/SemaTemplateVariadic.cpp
index 40522a07f6339c..79e2f1f610b11f 100644
--- a/clang/lib/Sema/SemaTemplateVariadic.cpp
+++ b/clang/lib/Sema/SemaTemplateVariadic.cpp
@@ -1211,7 +1211,9 @@ TemplateArgumentLoc Sema::getTemplateArgumentPackExpansionPattern(
   llvm_unreachable("Invalid TemplateArgument Kind!");
 }
 
-std::optional<unsigned> Sema::getFullyPackExpandedSize(TemplateArgument Arg) {
+std::optional<unsigned>
+Sema::getFullyPackExpandedSize(TemplateArgument Arg,
+                               const NamedDecl *&ParameterPack) {
   assert(Arg.containsUnexpandedParameterPack());
 
   // If this is a substituted pack, grab that pack. If not, we don't know
@@ -1222,17 +1224,20 @@ std::optional<unsigned> Sema::getFullyPackExpandedSize(TemplateArgument Arg) {
   TemplateArgument Pack;
   switch (Arg.getKind()) {
   case TemplateArgument::Type:
-    if (auto *Subst = Arg.getAsType()->getAs<SubstTemplateTypeParmPackType>())
+    if (auto *Subst = Arg.getAsType()->getAs<SubstTemplateTypeParmPackType>()) {
       Pack = Subst->getArgumentPack();
-    else
+      ParameterPack = Subst->getReplacedParameter();
+    } else
       return std::nullopt;
     break;
 
   case TemplateArgument::Expression:
     if (auto *Subst =
-            dyn_cast<SubstNonTypeTemplateParmPackExpr>(Arg.getAsExpr()))
+            dyn_cast<SubstNonTypeTemplateParmPackExpr>(Arg.getAsExpr())) {
       Pack = Subst->getArgumentPack();
-    else if (auto *Subst = dyn_cast<FunctionParmPackExpr>(Arg.getAsExpr()))  {
+      ParameterPack = Subst->getParameterPack();
+    } else if (auto *Subst = dyn_cast<FunctionParmPackExpr>(Arg.getAsExpr())) {
+      ParameterPack = Subst->getParameterPack();
       for (VarDecl *PD : *Subst)
         if (PD->isParameterPack())
           return std::nullopt;
@@ -1243,9 +1248,10 @@ std::optional<unsigned> Sema::getFullyPackExpandedSize(TemplateArgument Arg) {
 
   case TemplateArgument::Template:
     if (SubstTemplateTemplateParmPackStorage *Subst =
-            Arg.getAsTemplate().getAsSubstTemplateTemplateParmPack())
+            Arg.getAsTemplate().getAsSubstTemplateTemplateParmPack()) {
       Pack = Subst->getArgumentPack();
-    else
+      ParameterPack = Subst->getParameterPack();
+    } else
       return std::nullopt;
     break;
 
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 91cb980ee26b26..3a029e88e865df 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -15237,6 +15237,7 @@ TreeTransform<Derived>::TransformSizeOfPackExpr(SizeOfPackExpr *E) {
 
   // Try to compute the result without performing a partial substitution.
   std::optional<unsigned> Result = 0;
+  NamedDecl *NewPack = E->getPack();
   for (const TemplateArgument &Arg : PackArgs) {
     if (!Arg.isPackExpansion()) {
       Result = *Result + 1;
@@ -15260,9 +15261,14 @@ TreeTransform<Derived>::TransformSizeOfPackExpr(SizeOfPackExpr *E) {
                                                /*Uneval*/ true))
       return true;
 
+    const NamedDecl *TransformedParameterPack = nullptr;
     // See if we can determine the number of arguments from the result.
-    std::optional<unsigned> NumExpansions =
-        getSema().getFullyPackExpandedSize(OutPattern.getArgument());
+    std::optional<unsigned> NumExpansions = getSema().getFullyPackExpandedSize(
+        OutPattern.getArgument(), TransformedParameterPack);
+    if (TransformedParameterPack && !E->isPartiallySubstituted()) {
+      assert(PackArgs.size() == 1);
+      NewPack = const_cast<NamedDecl *>(TransformedParameterPack);
+    }
     if (!NumExpansions) {
       // No: we must be in an alias template expansion, and we're going to need
       // to actually expand the packs.
@@ -15277,7 +15283,7 @@ TreeTransform<Derived>::TransformSizeOfPackExpr(SizeOfPackExpr *E) {
   // substituting.
   if (Result)
     return getDerived().RebuildSizeOfPackExpr(
-        E->getOperatorLoc(), E->getPack(), E->getPackLoc(), E->getRParenLoc(),
+        E->getOperatorLoc(), NewPack, E->getPackLoc(), E->getRParenLoc(),
         *Result, std::nullopt);
 
   TemplateArgumentListInfo TransformedPackArgs(E->getPackLoc(),
@@ -15304,10 +15310,10 @@ TreeTransform<Derived>::TransformSizeOfPackExpr(SizeOfPackExpr *E) {
 
   if (PartialSubstitution)
     return getDerived().RebuildSizeOfPackExpr(
-        E->getOperatorLoc(), E->getPack(), E->getPackLoc(), E->getRParenLoc(),
+        E->getOperatorLoc(), NewPack, E->getPackLoc(), E->getRParenLoc(),
         std::nullopt, Args);
 
-  return getDerived().RebuildSizeOfPackExpr(E->getOperatorLoc(), E->getPack(),
+  return getDerived().RebuildSizeOfPackExpr(E->getOperatorLoc(), NewPack,
                                             E->getPackLoc(), E->getRParenLoc(),
                                             Args.size(), std::nullopt);
 }
diff --git a/clang/test/SemaTemplate/concepts-out-of-line-def.cpp b/clang/test/SemaTemplate/concepts-out-of-line-def.cpp
index 5450d105a6f54a..8ca399a0f729a9 100644
--- a/clang/test/SemaTemplate/concepts-out-of-line-def.cpp
+++ b/clang/test/SemaTemplate/concepts-out-of-line-def.cpp
@@ -666,3 +666,37 @@ int foo() {
 }
 
 } // namespace eve
+
+namespace GH93099 {
+
+// Issues with sizeof...(expr)
+
+template <typename T = int> struct C {
+  template <int... N>
+    requires(sizeof...(N) > 0)
+  friend class NTTP;
+
+  template <class... Tp>
+    requires(sizeof...(Tp) > 0)
+  friend class TP;
+
+  template <template <typename> class... TTp>
+    requires(sizeof...(TTp) > 0)
+  friend class TTP;
+};
+
+template <int... N>
+  requires(sizeof...(N) > 0)
+class NTTP;
+
+template <class... Tp>
+  requires(sizeof...(Tp) > 0)
+class TP;
+
+template <template <typename> class... TTp>
+  requires(sizeof...(TTp) > 0)
+class TTP;
+
+C v;
+
+} // namespace GH93099

>From e36ecb4ff45d97c445f3ac81b3df8bd2b8ddab14 Mon Sep 17 00:00:00 2001
From: Younan Zhang <zyn7109 at gmail.com>
Date: Fri, 27 Sep 2024 22:13:39 +0800
Subject: [PATCH 2/7] Fix CI - the associated Decls are wrong previously

---
 clang/lib/Sema/SemaTemplateInstantiate.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index fd51fa4afcacbf..3e8b04743c5562 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -371,7 +371,7 @@ Response HandleFunctionTemplateDecl(const FunctionTemplateDecl *FTD,
                   Specialization->getTemplateInstantiationArgs().asArray();
           }
           Result.addOuterTemplateArguments(
-              const_cast<FunctionTemplateDecl *>(FTD), Arguments,
+              TSTy->getTemplateName().getAsTemplateDecl(), Arguments,
               /*Final=*/false);
         }
       }

>From a798926c842c3562e2ad7252fd182a221f6bc4d6 Mon Sep 17 00:00:00 2001
From: Younan Zhang <zyn7109 at gmail.com>
Date: Sat, 28 Sep 2024 20:02:51 +0800
Subject: [PATCH 3/7] Revert "[Clang] GH93099"

This reverts commit 23a765ac6d8e455121346405332d2066dcc0861e.
---
 clang/include/clang/Sema/Sema.h               |  4 +--
 clang/lib/Sema/SemaTemplateVariadic.cpp       | 20 ++++-------
 clang/lib/Sema/TreeTransform.h                | 16 +++------
 .../SemaTemplate/concepts-out-of-line-def.cpp | 34 -------------------
 4 files changed, 13 insertions(+), 61 deletions(-)

diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 1fce74880026ce..e1c3a99cfa167e 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -14264,9 +14264,7 @@ class Sema final : public SemaBase {
   ///
   /// This is intended for use when transforming 'sizeof...(Arg)' in order to
   /// avoid actually expanding the pack where possible.
-  std::optional<unsigned>
-  getFullyPackExpandedSize(TemplateArgument Arg,
-                           const NamedDecl *&ParameterPack);
+  std::optional<unsigned> getFullyPackExpandedSize(TemplateArgument Arg);
 
   /// Called when an expression computing the size of a parameter pack
   /// is parsed.
diff --git a/clang/lib/Sema/SemaTemplateVariadic.cpp b/clang/lib/Sema/SemaTemplateVariadic.cpp
index 79e2f1f610b11f..40522a07f6339c 100644
--- a/clang/lib/Sema/SemaTemplateVariadic.cpp
+++ b/clang/lib/Sema/SemaTemplateVariadic.cpp
@@ -1211,9 +1211,7 @@ TemplateArgumentLoc Sema::getTemplateArgumentPackExpansionPattern(
   llvm_unreachable("Invalid TemplateArgument Kind!");
 }
 
-std::optional<unsigned>
-Sema::getFullyPackExpandedSize(TemplateArgument Arg,
-                               const NamedDecl *&ParameterPack) {
+std::optional<unsigned> Sema::getFullyPackExpandedSize(TemplateArgument Arg) {
   assert(Arg.containsUnexpandedParameterPack());
 
   // If this is a substituted pack, grab that pack. If not, we don't know
@@ -1224,20 +1222,17 @@ Sema::getFullyPackExpandedSize(TemplateArgument Arg,
   TemplateArgument Pack;
   switch (Arg.getKind()) {
   case TemplateArgument::Type:
-    if (auto *Subst = Arg.getAsType()->getAs<SubstTemplateTypeParmPackType>()) {
+    if (auto *Subst = Arg.getAsType()->getAs<SubstTemplateTypeParmPackType>())
       Pack = Subst->getArgumentPack();
-      ParameterPack = Subst->getReplacedParameter();
-    } else
+    else
       return std::nullopt;
     break;
 
   case TemplateArgument::Expression:
     if (auto *Subst =
-            dyn_cast<SubstNonTypeTemplateParmPackExpr>(Arg.getAsExpr())) {
+            dyn_cast<SubstNonTypeTemplateParmPackExpr>(Arg.getAsExpr()))
       Pack = Subst->getArgumentPack();
-      ParameterPack = Subst->getParameterPack();
-    } else if (auto *Subst = dyn_cast<FunctionParmPackExpr>(Arg.getAsExpr())) {
-      ParameterPack = Subst->getParameterPack();
+    else if (auto *Subst = dyn_cast<FunctionParmPackExpr>(Arg.getAsExpr()))  {
       for (VarDecl *PD : *Subst)
         if (PD->isParameterPack())
           return std::nullopt;
@@ -1248,10 +1243,9 @@ Sema::getFullyPackExpandedSize(TemplateArgument Arg,
 
   case TemplateArgument::Template:
     if (SubstTemplateTemplateParmPackStorage *Subst =
-            Arg.getAsTemplate().getAsSubstTemplateTemplateParmPack()) {
+            Arg.getAsTemplate().getAsSubstTemplateTemplateParmPack())
       Pack = Subst->getArgumentPack();
-      ParameterPack = Subst->getParameterPack();
-    } else
+    else
       return std::nullopt;
     break;
 
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 3a029e88e865df..91cb980ee26b26 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -15237,7 +15237,6 @@ TreeTransform<Derived>::TransformSizeOfPackExpr(SizeOfPackExpr *E) {
 
   // Try to compute the result without performing a partial substitution.
   std::optional<unsigned> Result = 0;
-  NamedDecl *NewPack = E->getPack();
   for (const TemplateArgument &Arg : PackArgs) {
     if (!Arg.isPackExpansion()) {
       Result = *Result + 1;
@@ -15261,14 +15260,9 @@ TreeTransform<Derived>::TransformSizeOfPackExpr(SizeOfPackExpr *E) {
                                                /*Uneval*/ true))
       return true;
 
-    const NamedDecl *TransformedParameterPack = nullptr;
     // See if we can determine the number of arguments from the result.
-    std::optional<unsigned> NumExpansions = getSema().getFullyPackExpandedSize(
-        OutPattern.getArgument(), TransformedParameterPack);
-    if (TransformedParameterPack && !E->isPartiallySubstituted()) {
-      assert(PackArgs.size() == 1);
-      NewPack = const_cast<NamedDecl *>(TransformedParameterPack);
-    }
+    std::optional<unsigned> NumExpansions =
+        getSema().getFullyPackExpandedSize(OutPattern.getArgument());
     if (!NumExpansions) {
       // No: we must be in an alias template expansion, and we're going to need
       // to actually expand the packs.
@@ -15283,7 +15277,7 @@ TreeTransform<Derived>::TransformSizeOfPackExpr(SizeOfPackExpr *E) {
   // substituting.
   if (Result)
     return getDerived().RebuildSizeOfPackExpr(
-        E->getOperatorLoc(), NewPack, E->getPackLoc(), E->getRParenLoc(),
+        E->getOperatorLoc(), E->getPack(), E->getPackLoc(), E->getRParenLoc(),
         *Result, std::nullopt);
 
   TemplateArgumentListInfo TransformedPackArgs(E->getPackLoc(),
@@ -15310,10 +15304,10 @@ TreeTransform<Derived>::TransformSizeOfPackExpr(SizeOfPackExpr *E) {
 
   if (PartialSubstitution)
     return getDerived().RebuildSizeOfPackExpr(
-        E->getOperatorLoc(), NewPack, E->getPackLoc(), E->getRParenLoc(),
+        E->getOperatorLoc(), E->getPack(), E->getPackLoc(), E->getRParenLoc(),
         std::nullopt, Args);
 
-  return getDerived().RebuildSizeOfPackExpr(E->getOperatorLoc(), NewPack,
+  return getDerived().RebuildSizeOfPackExpr(E->getOperatorLoc(), E->getPack(),
                                             E->getPackLoc(), E->getRParenLoc(),
                                             Args.size(), std::nullopt);
 }
diff --git a/clang/test/SemaTemplate/concepts-out-of-line-def.cpp b/clang/test/SemaTemplate/concepts-out-of-line-def.cpp
index 8ca399a0f729a9..5450d105a6f54a 100644
--- a/clang/test/SemaTemplate/concepts-out-of-line-def.cpp
+++ b/clang/test/SemaTemplate/concepts-out-of-line-def.cpp
@@ -666,37 +666,3 @@ int foo() {
 }
 
 } // namespace eve
-
-namespace GH93099 {
-
-// Issues with sizeof...(expr)
-
-template <typename T = int> struct C {
-  template <int... N>
-    requires(sizeof...(N) > 0)
-  friend class NTTP;
-
-  template <class... Tp>
-    requires(sizeof...(Tp) > 0)
-  friend class TP;
-
-  template <template <typename> class... TTp>
-    requires(sizeof...(TTp) > 0)
-  friend class TTP;
-};
-
-template <int... N>
-  requires(sizeof...(N) > 0)
-class NTTP;
-
-template <class... Tp>
-  requires(sizeof...(Tp) > 0)
-class TP;
-
-template <template <typename> class... TTp>
-  requires(sizeof...(TTp) > 0)
-class TTP;
-
-C v;
-
-} // namespace GH93099

>From 9c72edc5e119399f809eaed3acbd5018f538368c Mon Sep 17 00:00:00 2001
From: Younan Zhang <zyn7109 at gmail.com>
Date: Sat, 28 Sep 2024 21:56:37 +0800
Subject: [PATCH 4/7] Only transform SizeOfPackExprs' pack decls when
 normalizing constraints

---
 clang/include/clang/AST/ExprCXX.h             |  2 ++
 clang/lib/Sema/SemaConcept.cpp                | 14 +++++---
 clang/lib/Sema/SemaTemplateInstantiate.cpp    | 27 +++++++++++++++
 .../SemaTemplate/concepts-out-of-line-def.cpp | 34 +++++++++++++++++++
 4 files changed, 72 insertions(+), 5 deletions(-)

diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h
index 975bcdac5069b9..dfcf739ed1614f 100644
--- a/clang/include/clang/AST/ExprCXX.h
+++ b/clang/include/clang/AST/ExprCXX.h
@@ -4326,6 +4326,8 @@ class SizeOfPackExpr final
   /// Retrieve the parameter pack.
   NamedDecl *getPack() const { return Pack; }
 
+  void setPack(NamedDecl *NewPack) { Pack = NewPack; }
+
   /// Retrieve the length of the parameter pack.
   ///
   /// This routine may only be invoked when the expression is not
diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index 6a1b32598bb4a6..67fc603e9ce1d5 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -975,11 +975,14 @@ static const Expr *SubstituteConstraintExpressionWithoutSatisfaction(
   // parameters that the surrounding function hasn't been instantiated yet. Note
   // this may happen while we're comparing two templates' constraint
   // equivalence.
-  LocalInstantiationScope ScopeForParameters(S);
-  if (auto *FD = DeclInfo.getDecl()->getAsFunction())
+  std::optional<LocalInstantiationScope> ScopeForParameters;
+  if (const NamedDecl *ND = DeclInfo.getDecl();
+      ND && ND->isFunctionOrFunctionTemplate()) {
+    ScopeForParameters.emplace(S);
+    const FunctionDecl *FD = ND->getAsFunction();
     for (auto *PVD : FD->parameters()) {
       if (!PVD->isParameterPack()) {
-        ScopeForParameters.InstantiatedLocal(PVD, PVD);
+        ScopeForParameters->InstantiatedLocal(PVD, PVD);
         continue;
       }
       // This is hacky: we're mapping the parameter pack to a size-of-1 argument
@@ -998,9 +1001,10 @@ static const Expr *SubstituteConstraintExpressionWithoutSatisfaction(
       // that we can eliminate the Scope in the cases where the declarations are
       // not necessarily instantiated. It would also benefit the noexcept
       // specifier comparison.
-      ScopeForParameters.MakeInstantiatedLocalArgPack(PVD);
-      ScopeForParameters.InstantiatedLocalPackArg(PVD, PVD);
+      ScopeForParameters->MakeInstantiatedLocalArgPack(PVD);
+      ScopeForParameters->InstantiatedLocalPackArg(PVD, PVD);
     }
+  }
 
   std::optional<Sema::CXXThisScopeRAII> ThisScope;
 
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index 3e8b04743c5562..eaf8cb6b2dae10 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -18,6 +18,7 @@
 #include "clang/AST/DeclBase.h"
 #include "clang/AST/DeclTemplate.h"
 #include "clang/AST/Expr.h"
+#include "clang/AST/ExprCXX.h"
 #include "clang/AST/ExprConcepts.h"
 #include "clang/AST/PrettyDeclStackTrace.h"
 #include "clang/AST/RecursiveASTVisitor.h"
@@ -1722,6 +1723,32 @@ namespace {
       return inherited::TransformLambdaBody(E, Body);
     }
 
+    ExprResult TransformSizeOfPackExpr(SizeOfPackExpr *E) {
+      ExprResult Result = inherited::TransformSizeOfPackExpr(E);
+
+      if (SemaRef.CodeSynthesisContexts.back().Kind !=
+          Sema::CodeSynthesisContext::ConstraintNormalization)
+        return Result;
+
+      if (!Result.isUsable())
+        return Result;
+
+      SizeOfPackExpr *NewExpr = cast<SizeOfPackExpr>(Result.get());
+#ifndef NDEBUG
+      for (auto *Iter = TemplateArgs.begin(); Iter != TemplateArgs.end();
+           ++Iter)
+        for (const TemplateArgument &TA : Iter->Args)
+          assert(TA.getKind() != TemplateArgument::Pack || TA.pack_size() == 1);
+#endif
+      Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(SemaRef, 0);
+      Decl *NewDecl = TransformDecl(NewExpr->getPackLoc(), NewExpr->getPack());
+      if (!NewDecl)
+        return ExprError();
+
+      NewExpr->setPack(cast<NamedDecl>(NewDecl));
+      return NewExpr;
+    }
+
     ExprResult TransformRequiresExpr(RequiresExpr *E) {
       LocalInstantiationScope Scope(SemaRef, /*CombineWithOuterScope=*/true);
       ExprResult TransReq = inherited::TransformRequiresExpr(E);
diff --git a/clang/test/SemaTemplate/concepts-out-of-line-def.cpp b/clang/test/SemaTemplate/concepts-out-of-line-def.cpp
index 5450d105a6f54a..8ca399a0f729a9 100644
--- a/clang/test/SemaTemplate/concepts-out-of-line-def.cpp
+++ b/clang/test/SemaTemplate/concepts-out-of-line-def.cpp
@@ -666,3 +666,37 @@ int foo() {
 }
 
 } // namespace eve
+
+namespace GH93099 {
+
+// Issues with sizeof...(expr)
+
+template <typename T = int> struct C {
+  template <int... N>
+    requires(sizeof...(N) > 0)
+  friend class NTTP;
+
+  template <class... Tp>
+    requires(sizeof...(Tp) > 0)
+  friend class TP;
+
+  template <template <typename> class... TTp>
+    requires(sizeof...(TTp) > 0)
+  friend class TTP;
+};
+
+template <int... N>
+  requires(sizeof...(N) > 0)
+class NTTP;
+
+template <class... Tp>
+  requires(sizeof...(Tp) > 0)
+class TP;
+
+template <template <typename> class... TTp>
+  requires(sizeof...(TTp) > 0)
+class TTP;
+
+C v;
+
+} // namespace GH93099

>From 1e384b5c6cc4686e234ef85d6c25cc0d2e3184ec Mon Sep 17 00:00:00 2001
From: Younan Zhang <zyn7109 at gmail.com>
Date: Sat, 28 Sep 2024 21:58:41 +0800
Subject: [PATCH 5/7] Remove unnecessary includes

---
 clang/lib/Sema/SemaTemplateInstantiate.cpp | 1 -
 1 file changed, 1 deletion(-)

diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index eaf8cb6b2dae10..20215d32539af9 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -18,7 +18,6 @@
 #include "clang/AST/DeclBase.h"
 #include "clang/AST/DeclTemplate.h"
 #include "clang/AST/Expr.h"
-#include "clang/AST/ExprCXX.h"
 #include "clang/AST/ExprConcepts.h"
 #include "clang/AST/PrettyDeclStackTrace.h"
 #include "clang/AST/RecursiveASTVisitor.h"

>From 391696e33b7a990b23f89e1c8f631a2feed1809e Mon Sep 17 00:00:00 2001
From: Younan Zhang <zyn7109 at gmail.com>
Date: Sat, 28 Sep 2024 22:50:53 +0800
Subject: [PATCH 6/7] Add a release note

---
 clang/docs/ReleaseNotes.rst | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 1fbcac807d0b30..831dab0657fcaf 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -444,6 +444,8 @@ Bug Fixes to C++ Support
 - Fixed an assertion failure in debug mode, and potential crashes in release mode, when
   diagnosing a failed cast caused indirectly by a failed implicit conversion to the type of the constructor parameter.
 - Fixed an assertion failure by adjusting integral to boolean vector conversions (#GH108326)
+- Fixed a bug in constraint expression comparison where the ``sizeof...`` expression was not handled properly
+  in certain friend declarations. (#GH93099)
 
 Bug Fixes to AST Handling
 ^^^^^^^^^^^^^^^^^^^^^^^^^

>From 314469807d47049faa4bb3114ba25fc1b8d63bc1 Mon Sep 17 00:00:00 2001
From: Younan Zhang <zyn7109 at gmail.com>
Date: Sat, 28 Sep 2024 23:10:26 +0800
Subject: [PATCH 7/7] Use RebuildSizeOfPackExpr instead

---
 clang/include/clang/AST/ExprCXX.h          |  2 --
 clang/lib/Sema/SemaTemplateInstantiate.cpp | 24 +++++++++++-----------
 2 files changed, 12 insertions(+), 14 deletions(-)

diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h
index dfcf739ed1614f..975bcdac5069b9 100644
--- a/clang/include/clang/AST/ExprCXX.h
+++ b/clang/include/clang/AST/ExprCXX.h
@@ -4326,8 +4326,6 @@ class SizeOfPackExpr final
   /// Retrieve the parameter pack.
   NamedDecl *getPack() const { return Pack; }
 
-  void setPack(NamedDecl *NewPack) { Pack = NewPack; }
-
   /// Retrieve the length of the parameter pack.
   ///
   /// This routine may only be invoked when the expression is not
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index 20215d32539af9..16110629a36d02 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -1722,17 +1722,16 @@ namespace {
       return inherited::TransformLambdaBody(E, Body);
     }
 
-    ExprResult TransformSizeOfPackExpr(SizeOfPackExpr *E) {
-      ExprResult Result = inherited::TransformSizeOfPackExpr(E);
-
+    ExprResult RebuildSizeOfPackExpr(SourceLocation OperatorLoc,
+                                     NamedDecl *Pack, SourceLocation PackLoc,
+                                     SourceLocation RParenLoc,
+                                     std::optional<unsigned> Length,
+                                     ArrayRef<TemplateArgument> PartialArgs) {
       if (SemaRef.CodeSynthesisContexts.back().Kind !=
           Sema::CodeSynthesisContext::ConstraintNormalization)
-        return Result;
-
-      if (!Result.isUsable())
-        return Result;
+        return inherited::RebuildSizeOfPackExpr(OperatorLoc, Pack, PackLoc,
+                                                RParenLoc, Length, PartialArgs);
 
-      SizeOfPackExpr *NewExpr = cast<SizeOfPackExpr>(Result.get());
 #ifndef NDEBUG
       for (auto *Iter = TemplateArgs.begin(); Iter != TemplateArgs.end();
            ++Iter)
@@ -1740,12 +1739,13 @@ namespace {
           assert(TA.getKind() != TemplateArgument::Pack || TA.pack_size() == 1);
 #endif
       Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(SemaRef, 0);
-      Decl *NewDecl = TransformDecl(NewExpr->getPackLoc(), NewExpr->getPack());
-      if (!NewDecl)
+      Decl *NewPack = TransformDecl(PackLoc, Pack);
+      if (!NewPack)
         return ExprError();
 
-      NewExpr->setPack(cast<NamedDecl>(NewDecl));
-      return NewExpr;
+      return inherited::RebuildSizeOfPackExpr(OperatorLoc,
+                                              cast<NamedDecl>(NewPack), PackLoc,
+                                              RParenLoc, Length, PartialArgs);
     }
 
     ExprResult TransformRequiresExpr(RequiresExpr *E) {



More information about the cfe-commits mailing list