[clang] [Clang] GH93099 (PR #110238)

Younan Zhang via cfe-commits cfe-commits at lists.llvm.org
Fri Sep 27 03:26:48 PDT 2024


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

Fixes #93099 

>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] [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



More information about the cfe-commits mailing list