Skip to content

[Clang] Fix pack indexing profiling #139276

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
May 9, 2025
Merged

Conversation

cor3ntin
Copy link
Contributor

@cor3ntin cor3ntin commented May 9, 2025

When profiling a pack indexing that has been partially substituted, we should profile the expansions, rather than the pattern itseld

This is a better approach to #139057

This mirrors the fix done for SizeOfPackExpr in #124533

Fixes #138255

When profiling a pack indexing that has been partially
substituted, we should profile the expansions, rather than
the pattern itseld

This is a better approach to llvm#139057

This mirrors the fix done for SizeOfPackExpr in llvm#124533

Fixes llvm#138255
@cor3ntin cor3ntin requested a review from erichkeane May 9, 2025 14:55
@llvmbot llvmbot added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" clang:modules C++20 modules and Clang Header Modules labels May 9, 2025
@cor3ntin cor3ntin requested a review from zyn0217 May 9, 2025 14:55
@llvmbot
Copy link
Member

llvmbot commented May 9, 2025

@llvm/pr-subscribers-clang

@llvm/pr-subscribers-clang-modules

Author: cor3ntin (cor3ntin)

Changes

When profiling a pack indexing that has been partially substituted, we should profile the expansions, rather than the pattern itseld

This is a better approach to #139057

This mirrors the fix done for SizeOfPackExpr in #124533

Fixes #138255


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

8 Files Affected:

  • (modified) clang/docs/ReleaseNotes.rst (+1)
  • (modified) clang/include/clang/AST/ASTContext.h (+2-1)
  • (modified) clang/include/clang/AST/ExprCXX.h (+4)
  • (modified) clang/include/clang/AST/Type.h (+5-11)
  • (modified) clang/lib/AST/ASTContext.cpp (+4-4)
  • (modified) clang/lib/AST/StmtProfile.cpp (+8-2)
  • (modified) clang/lib/AST/Type.cpp (+20-6)
  • (modified) clang/test/SemaTemplate/concepts-out-of-line-def.cpp (+75-1)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index c52e285bde627..938d9578bae61 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -667,6 +667,7 @@ Bug Fixes to C++ Support
   whose type depends on itself. (#GH51347), (#GH55872)
 - Improved parser recovery of invalid requirement expressions. In turn, this
   fixes crashes from follow-on processing of the invalid requirement. (#GH138820)
+- Fixed the handling of pack indexing types in the constraints of a member function redeclaration. (#GH138255)
 
 Bug Fixes to AST Handling
 ^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h
index e107db458742e..1fdc488a76507 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -221,7 +221,8 @@ class ASTContext : public RefCountedBase<ASTContext> {
   mutable llvm::ContextualFoldingSet<DependentDecltypeType, ASTContext &>
       DependentDecltypeTypes;
 
-  mutable llvm::FoldingSet<PackIndexingType> DependentPackIndexingTypes;
+  mutable llvm::ContextualFoldingSet<PackIndexingType, ASTContext &>
+      DependentPackIndexingTypes;
 
   mutable llvm::FoldingSet<TemplateTypeParmType> TemplateTypeParmTypes;
   mutable llvm::FoldingSet<ObjCTypeParamType> ObjCTypeParamTypes;
diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h
index 8710f252a0c5c..e4b2e3486ec27 100644
--- a/clang/include/clang/AST/ExprCXX.h
+++ b/clang/include/clang/AST/ExprCXX.h
@@ -4549,6 +4549,10 @@ class PackIndexingExpr final
 
   bool isFullySubstituted() const { return FullySubstituted; }
 
+  bool isPartiallySubstituted() const {
+    return isValueDependent() && TransformedExpressions;
+  };
+
   /// Determine if the expression was expanded to empty.
   bool expandsToEmptyPack() const {
     return isFullySubstituted() && TransformedExpressions == 0;
diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h
index 773796a55eaa1..242d7b72bd5b8 100644
--- a/clang/include/clang/AST/Type.h
+++ b/clang/include/clang/AST/Type.h
@@ -5976,7 +5976,6 @@ class PackIndexingType final
       private llvm::TrailingObjects<PackIndexingType, QualType> {
   friend TrailingObjects;
 
-  const ASTContext &Context;
   QualType Pattern;
   Expr *IndexExpr;
 
@@ -5987,9 +5986,8 @@ class PackIndexingType final
 
 protected:
   friend class ASTContext; // ASTContext creates these.
-  PackIndexingType(const ASTContext &Context, QualType Canonical,
-                   QualType Pattern, Expr *IndexExpr, bool FullySubstituted,
-                   ArrayRef<QualType> Expansions = {});
+  PackIndexingType(QualType Canonical, QualType Pattern, Expr *IndexExpr,
+                   bool FullySubstituted, ArrayRef<QualType> Expansions = {});
 
 public:
   Expr *getIndexExpr() const { return IndexExpr; }
@@ -6024,14 +6022,10 @@ class PackIndexingType final
     return T->getTypeClass() == PackIndexing;
   }
 
-  void Profile(llvm::FoldingSetNodeID &ID) {
-    if (hasSelectedType())
-      getSelectedType().Profile(ID);
-    else
-      Profile(ID, Context, getPattern(), getIndexExpr(), isFullySubstituted());
-  }
+  void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context);
   static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context,
-                      QualType Pattern, Expr *E, bool FullySubstituted);
+                      QualType Pattern, Expr *E, bool FullySubstituted,
+                      ArrayRef<QualType> Expansions);
 
 private:
   const QualType *getExpansionsPtr() const {
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index 1ed16748dff1a..14f4994f1688f 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -940,7 +940,7 @@ ASTContext::ASTContext(LangOptions &LOpts, SourceManager &SM,
       DependentSizedMatrixTypes(this_()),
       FunctionProtoTypes(this_(), FunctionProtoTypesLog2InitSize),
       DependentTypeOfExprTypes(this_()), DependentDecltypeTypes(this_()),
-      TemplateSpecializationTypes(this_()),
+      DependentPackIndexingTypes(this_()), TemplateSpecializationTypes(this_()),
       DependentTemplateSpecializationTypes(this_()),
       DependentBitIntTypes(this_()), SubstTemplateTemplateParmPacks(this_()),
       DeducedTemplates(this_()), ArrayParameterTypes(this_()),
@@ -6438,7 +6438,7 @@ QualType ASTContext::getPackIndexingType(QualType Pattern, Expr *IndexExpr,
   } else {
     llvm::FoldingSetNodeID ID;
     PackIndexingType::Profile(ID, *this, Pattern.getCanonicalType(), IndexExpr,
-                              FullySubstituted);
+                              FullySubstituted, Expansions);
     void *InsertPos = nullptr;
     PackIndexingType *Canon =
         DependentPackIndexingTypes.FindNodeOrInsertPos(ID, InsertPos);
@@ -6447,7 +6447,7 @@ QualType ASTContext::getPackIndexingType(QualType Pattern, Expr *IndexExpr,
           PackIndexingType::totalSizeToAlloc<QualType>(Expansions.size()),
           TypeAlignment);
       Canon = new (Mem)
-          PackIndexingType(*this, QualType(), Pattern.getCanonicalType(),
+          PackIndexingType(QualType(), Pattern.getCanonicalType(),
                            IndexExpr, FullySubstituted, Expansions);
       DependentPackIndexingTypes.InsertNode(Canon, InsertPos);
     }
@@ -6457,7 +6457,7 @@ QualType ASTContext::getPackIndexingType(QualType Pattern, Expr *IndexExpr,
   void *Mem =
       Allocate(PackIndexingType::totalSizeToAlloc<QualType>(Expansions.size()),
                TypeAlignment);
-  auto *T = new (Mem) PackIndexingType(*this, Canonical, Pattern, IndexExpr,
+  auto *T = new (Mem) PackIndexingType(Canonical, Pattern, IndexExpr,
                                        FullySubstituted, Expansions);
   Types.push_back(T);
   return QualType(T, 0);
diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp
index 83d54da9be7e5..2483ca36b77ea 100644
--- a/clang/lib/AST/StmtProfile.cpp
+++ b/clang/lib/AST/StmtProfile.cpp
@@ -2291,9 +2291,15 @@ void StmtProfiler::VisitSizeOfPackExpr(const SizeOfPackExpr *S) {
 }
 
 void StmtProfiler::VisitPackIndexingExpr(const PackIndexingExpr *E) {
-  VisitExpr(E);
-  VisitExpr(E->getPackIdExpression());
   VisitExpr(E->getIndexExpr());
+
+  if (E->isPartiallySubstituted()) {
+    ID.AddInteger(E->getExpressions().size());
+    for (const Expr *Sub : E->getExpressions())
+      Visit(Sub);
+  } else {
+    VisitExpr(E->getPackIdExpression());
+  }
 }
 
 void StmtProfiler::VisitSubstNonTypeTemplateParmPackExpr(
diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp
index 31e4bcd7535ea..93da9d31083db 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -4126,14 +4126,14 @@ void DependentDecltypeType::Profile(llvm::FoldingSetNodeID &ID,
   E->Profile(ID, Context, true);
 }
 
-PackIndexingType::PackIndexingType(const ASTContext &Context,
-                                   QualType Canonical, QualType Pattern,
+PackIndexingType::PackIndexingType(QualType Canonical, QualType Pattern,
                                    Expr *IndexExpr, bool FullySubstituted,
                                    ArrayRef<QualType> Expansions)
     : Type(PackIndexing, Canonical,
            computeDependence(Pattern, IndexExpr, Expansions)),
-      Context(Context), Pattern(Pattern), IndexExpr(IndexExpr),
-      Size(Expansions.size()), FullySubstituted(FullySubstituted) {
+      Pattern(Pattern), IndexExpr(IndexExpr), Size(Expansions.size()),
+      FullySubstituted(FullySubstituted) {
+
   llvm::uninitialized_copy(Expansions, getTrailingObjects<QualType>());
 }
 
@@ -4174,12 +4174,26 @@ PackIndexingType::computeDependence(QualType Pattern, Expr *IndexExpr,
   return TD;
 }
 
+void PackIndexingType::Profile(llvm::FoldingSetNodeID &ID,
+                               const ASTContext &Context) {
+  Profile(ID, Context, getPattern(), getIndexExpr(), isFullySubstituted(), getExpansions());
+}
+
 void PackIndexingType::Profile(llvm::FoldingSetNodeID &ID,
                                const ASTContext &Context, QualType Pattern,
-                               Expr *E, bool FullySubstituted) {
-  Pattern.Profile(ID);
+                               Expr *E, bool FullySubstituted,
+                               ArrayRef<QualType> Expansions) {
+
   E->Profile(ID, Context, true);
   ID.AddBoolean(FullySubstituted);
+  if(!Expansions.empty()) {
+    ID.AddInteger(Expansions.size());
+    for(QualType T : Expansions)
+      T.getCanonicalType().Profile(ID);
+  }
+  else {
+    Pattern.Profile(ID);
+  }
 }
 
 UnaryTransformType::UnaryTransformType(QualType BaseType,
diff --git a/clang/test/SemaTemplate/concepts-out-of-line-def.cpp b/clang/test/SemaTemplate/concepts-out-of-line-def.cpp
index 5af4ec75cae90..e5d00491d3fb8 100644
--- a/clang/test/SemaTemplate/concepts-out-of-line-def.cpp
+++ b/clang/test/SemaTemplate/concepts-out-of-line-def.cpp
@@ -1,4 +1,6 @@
-// RUN: %clang_cc1 -std=c++20 -verify %s
+// RUN: %clang_cc1 -std=c++20 -Wno-c++26-extensions -verify %s
+// RUN: %clang_cc1 -std=c++2c -Wno-c++26-extensions -verify %s
+
 
 static constexpr int PRIMARY = 0;
 static constexpr int SPECIALIZATION_CONCEPT = 1;
@@ -779,3 +781,75 @@ template <typename T>
 consteval void S::mfn() requires (bool(&fn)) {}
 
 }
+
+
+namespace GH138255 {
+
+template <typename... T>
+concept C = true;
+
+struct Func {
+  template<typename... Ts>
+  requires C<Ts...[0]>
+  static auto buggy() -> void;
+
+  template<typename... Ts>
+  requires C<Ts...[0]>
+  friend auto fr() -> void;
+
+  template<typename... Ts>
+  requires C<Ts...[0]>
+  friend auto fr2() -> void{}; // expected-note{{previous definition is here}}
+};
+
+template<typename... Ts>
+requires C<Ts...[0]>
+auto Func::buggy() -> void {}
+
+template<typename... Ts>
+requires C<Ts...[0]>
+auto fr() -> void {}
+
+template<typename... Ts>
+requires C<Ts...[0]>
+auto fr2() -> void {} // expected-error{{redefinition of 'fr2'}}
+
+
+template <typename... Ts>
+requires C<Ts...[0]>
+struct Class;
+
+template <typename... Ts>
+requires C<Ts...[0]>
+struct Class;
+
+
+template <typename...>
+struct TplClass {
+  template<typename... Ts>
+  requires C<Ts...[0]>
+  static auto buggy() -> void;
+};
+
+template<>
+template<typename... Ts>
+requires C<Ts...[0]>
+auto TplClass<int>::buggy() -> void {}
+
+}
+
+namespace PackIndexExpr {
+template <int... T>
+concept C = true;
+
+template <typename...> struct TplClass {
+  template <int... Ts>
+  requires C<Ts...[0]>
+  static auto buggy() -> void;
+};
+
+template <>
+template <int... Ts>
+requires C<Ts...[0]>
+auto TplClass<int>::buggy() -> void {}
+}

Copy link
Collaborator

@erichkeane erichkeane left a comment

Choose a reason for hiding this comment

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

I like this better too.

Copy link

github-actions bot commented May 9, 2025

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

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.

Thanks for the iteration!

@@ -4549,6 +4549,10 @@ class PackIndexingExpr final

bool isFullySubstituted() const { return FullySubstituted; }

bool isPartiallySubstituted() const {
return isValueDependent() && TransformedExpressions;
};
Copy link
Contributor

Choose a reason for hiding this comment

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

Trailing semicolon

@@ -4549,6 +4549,10 @@ class PackIndexingExpr final

bool isFullySubstituted() const { return FullySubstituted; }

bool isPartiallySubstituted() const {
Copy link
Contributor

Choose a reason for hiding this comment

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

Please document the difference with FullySubstituted

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I got rid of it entierly, it's cleaner

@cor3ntin cor3ntin merged commit 0077d4c into llvm:main May 9, 2025
10 of 11 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:modules C++20 modules and Clang Header Modules clang Clang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Pack indexing specifier can't be used with templated function declaration inside a class
4 participants