[clang] [Sema] 81145 (PR #81150)

Younan Zhang via cfe-commits cfe-commits at lists.llvm.org
Sun Feb 11 06:59:47 PST 2024


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

>From d9fe7f3777a27057181eaa008577fc13a30d30ee Mon Sep 17 00:00:00 2001
From: Younan Zhang <zyn7109 at gmail.com>
Date: Sat, 10 Feb 2024 15:34:36 +0800
Subject: [PATCH 1/3] fixup

---
 clang/include/clang/AST/DeclCXX.h           |  6 ++++
 clang/lib/AST/DeclCXX.cpp                   | 12 +++++++
 clang/lib/Sema/SemaTemplateInstantiate.cpp  | 24 ++++++++++++-
 clang/lib/Sema/TreeTransform.h              |  3 ++
 clang/test/SemaTemplate/concepts-lambda.cpp | 39 +++++++++++++++++++++
 5 files changed, 83 insertions(+), 1 deletion(-)

diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h
index 9cebaff63bb0db..a2c56b3c4cf2ac 100644
--- a/clang/include/clang/AST/DeclCXX.h
+++ b/clang/include/clang/AST/DeclCXX.h
@@ -426,6 +426,8 @@ class CXXRecordDecl : public RecordDecl {
     /// or within a data member initializer.
     LazyDeclPtr ContextDecl;
 
+    LazyDeclPtr InstantiatingContextDecl;
+
     /// The lists of captures, both explicit and implicit, for this
     /// lambda. One list is provided for each merged copy of the lambda.
     /// The first list corresponds to the canonical definition.
@@ -1786,6 +1788,10 @@ class CXXRecordDecl : public RecordDecl {
   /// the declaration context suffices.
   Decl *getLambdaContextDecl() const;
 
+  void setLambdaInstantiatingContextDecl(Decl *D);
+
+  Decl *getLambdaInstantiatingContextDecl() const;
+
   /// Retrieve the index of this lambda within the context declaration returned
   /// by getLambdaContextDecl().
   unsigned getLambdaIndexInContext() const {
diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp
index 117e802dae2d9d..9260be78aeefaa 100644
--- a/clang/lib/AST/DeclCXX.cpp
+++ b/clang/lib/AST/DeclCXX.cpp
@@ -1685,6 +1685,16 @@ Decl *CXXRecordDecl::getLambdaContextDecl() const {
   return getLambdaData().ContextDecl.get(Source);
 }
 
+Decl *CXXRecordDecl::getLambdaInstantiatingContextDecl() const {
+  assert(isLambda() && "Not a lambda closure type!");
+  ExternalASTSource *Source = getParentASTContext().getExternalSource();
+  return getLambdaData().InstantiatingContextDecl.get(Source);
+}
+
+void CXXRecordDecl::setLambdaInstantiatingContextDecl(Decl *D) {
+  getLambdaData().InstantiatingContextDecl = D;
+}
+
 void CXXRecordDecl::setLambdaNumbering(LambdaNumbering Numbering) {
   assert(isLambda() && "Not a lambda closure type!");
   getLambdaData().ManglingNumber = Numbering.ManglingNumber;
@@ -1693,6 +1703,8 @@ void CXXRecordDecl::setLambdaNumbering(LambdaNumbering Numbering) {
         Numbering.DeviceManglingNumber;
   getLambdaData().IndexInContext = Numbering.IndexInContext;
   getLambdaData().ContextDecl = Numbering.ContextDecl;
+  if (Numbering.ContextDecl)
+    getLambdaData().InstantiatingContextDecl = Numbering.ContextDecl;
   getLambdaData().HasKnownInternalLinkage = Numbering.HasKnownInternalLinkage;
 }
 
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index 6d59180bc446d2..541bb4081d8f36 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -314,7 +314,7 @@ Response HandleRecordDecl(const CXXRecordDecl *Rec,
   // This is to make sure we pick up the VarTemplateSpecializationDecl that this
   // lambda is defined inside of.
   if (Rec->isLambda())
-    if (const Decl *LCD = Rec->getLambdaContextDecl())
+    if (const Decl *LCD = Rec->getLambdaInstantiatingContextDecl())
       return Response::ChangeDecl(LCD);
 
   return Response::UseNextDecl(Rec);
@@ -330,6 +330,14 @@ Response HandleImplicitConceptSpecializationDecl(
   return Response::UseNextDecl(CSD);
 }
 
+Response HandleTypeAliasTemplateDecl(const TypeAliasTemplateDecl *TATD,
+                                     bool ForConstraintInstantiation,
+                                     MultiLevelTemplateArgumentList &Result) {
+  if (ForConstraintInstantiation)
+    Result.addOuterTemplateArguments(std::nullopt);
+  return Response::UseNextDecl(TATD);
+}
+
 Response HandleGenericDeclContext(const Decl *CurDecl) {
   return Response::UseNextDecl(CurDecl);
 }
@@ -425,6 +433,10 @@ MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs(
       if (const auto *TTP = dyn_cast<TemplateTemplateParmDecl>(CurDecl)) {
         R = HandleDefaultTempArgIntoTempTempParam(TTP, Result);
       }
+      if (const auto *TAD = dyn_cast<TypeAliasTemplateDecl>(CurDecl)) {
+        R = HandleTypeAliasTemplateDecl(TAD, ForConstraintInstantiation,
+                                        Result);
+      }
     } else {
       R = HandleGenericDeclContext(CurDecl);
     }
@@ -1231,6 +1243,8 @@ namespace {
     // Whether to evaluate the C++20 constraints or simply substitute into them.
     bool EvaluateConstraints = true;
 
+    llvm::DenseMap<Decl *, Decl *> InstantiatedLambdas;
+
   public:
     typedef TreeTransform<TemplateInstantiator> inherited;
 
@@ -1353,6 +1367,7 @@ namespace {
       auto *NewMD = dyn_cast<CXXMethodDecl>(New);
       if (NewMD && isLambdaCallOperator(NewMD)) {
         auto *OldMD = dyn_cast<CXXMethodDecl>(Old);
+        InstantiatedLambdas[OldMD] = NewMD;
         if (auto *NewTD = NewMD->getDescribedFunctionTemplate())
           NewTD->setInstantiatedFromMemberTemplate(
               OldMD->getDescribedFunctionTemplate());
@@ -1663,6 +1678,13 @@ Decl *TemplateInstantiator::TransformDecl(SourceLocation Loc, Decl *D) {
     // template parameter.
   }
 
+  if (auto *FTD = dyn_cast<FunctionTemplateDecl>(D))
+    if (auto *Method = dyn_cast<CXXMethodDecl>(FTD->getTemplatedDecl());
+        Method && isLambdaCallOperator(Method))
+      if (auto Iter = InstantiatedLambdas.find(Method);
+          Iter != InstantiatedLambdas.end())
+        return Iter->second;
+
   return SemaRef.FindInstantiatedDecl(Loc, cast<NamedDecl>(D), TemplateArgs);
 }
 
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 3ed17c3360a83c..95bf67fa4bef0e 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -13837,6 +13837,9 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
     }
 
     getSema().handleLambdaNumbering(Class, NewCallOperator, Numbering);
+    if (!Class->getLambdaInstantiatingContextDecl() && getSema().inTemplateInstantiation())
+      Class->setLambdaInstantiatingContextDecl(
+          getSema().CodeSynthesisContexts.back().Entity);
   }
 
   // FIXME: Sema's lambda-building mechanism expects us to push an expression
diff --git a/clang/test/SemaTemplate/concepts-lambda.cpp b/clang/test/SemaTemplate/concepts-lambda.cpp
index 0b7580f91043c7..1694f46fea8fdf 100644
--- a/clang/test/SemaTemplate/concepts-lambda.cpp
+++ b/clang/test/SemaTemplate/concepts-lambda.cpp
@@ -150,6 +150,45 @@ void foo() {
 }
 } // namespace ReturnTypeRequirementInLambda
 
+namespace GH70601 {
+
+template <class>
+concept C = true;
+
+template <class T, class U>
+concept D = C<T> && C<U>;
+
+template <class T>
+auto declval() -> decltype(T());
+
+template <class T>
+struct S {
+  template <class U>
+  using Type = decltype([]<C V>(V) {
+    return []<D<V> W> {
+      return W();
+    }.template operator()<V>();
+  }(U()));
+
+  template <C U>
+  using ValueType = decltype([]<D<U> V> {
+    return V();
+  }.template operator()<U>());
+
+  // template <C U>
+  // using LambdaType = decltype([]<D<U> V> {
+  //   return V();
+  // });
+
+  // using IndirectValueType = decltype(declval<LambdaType<T>>().template operator()<T>());
+};
+
+static_assert(__is_same(S<int>::Type<int>, int));
+static_assert(__is_same(S<int>::ValueType<float>, float));
+// static_assert(__is_same(S<char>::IndirectValueType, char));
+
+}
+
 namespace GH73418 {
 void foo() {
   int x;

>From 45e25a81809cfd4e0bcce27d85d004a893aeb5ad Mon Sep 17 00:00:00 2001
From: Younan Zhang <zyn7109 at gmail.com>
Date: Sat, 10 Feb 2024 15:35:43 +0800
Subject: [PATCH 2/3] format

---
 clang/lib/Sema/TreeTransform.h | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 95bf67fa4bef0e..0a1dad4df8cd94 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -13837,7 +13837,8 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
     }
 
     getSema().handleLambdaNumbering(Class, NewCallOperator, Numbering);
-    if (!Class->getLambdaInstantiatingContextDecl() && getSema().inTemplateInstantiation())
+    if (!Class->getLambdaInstantiatingContextDecl() &&
+        getSema().inTemplateInstantiation())
       Class->setLambdaInstantiatingContextDecl(
           getSema().CodeSynthesisContexts.back().Entity);
   }

>From 23d26a7fd09911845d46e145cd757f92278f218f Mon Sep 17 00:00:00 2001
From: Younan Zhang <zyn7109 at gmail.com>
Date: Sun, 11 Feb 2024 22:59:31 +0800
Subject: [PATCH 3/3] {read,writ}er

---
 clang/lib/Serialization/ASTReaderDecl.cpp | 20 ++++++++++++++------
 clang/lib/Serialization/ASTWriterDecl.cpp |  1 +
 2 files changed, 15 insertions(+), 6 deletions(-)

diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp
index ffba04f28782ea..f87d8113813442 100644
--- a/clang/lib/Serialization/ASTReaderDecl.cpp
+++ b/clang/lib/Serialization/ASTReaderDecl.cpp
@@ -161,10 +161,12 @@ namespace clang {
 
     void ReadCXXRecordDefinition(CXXRecordDecl *D, bool Update,
                                  Decl *LambdaContext = nullptr,
-                                 unsigned IndexInLambdaContext = 0);
+                                 unsigned IndexInLambdaContext = 0,
+                                 Decl *LambdaInstantiatingContext = nullptr);
     void ReadCXXDefinitionData(struct CXXRecordDecl::DefinitionData &Data,
                                const CXXRecordDecl *D, Decl *LambdaContext,
-                               unsigned IndexInLambdaContext);
+                               unsigned IndexInLambdaContext,
+                               Decl *LambdaInstantiatingContext);
     void MergeDefinitionData(CXXRecordDecl *D,
                              struct CXXRecordDecl::DefinitionData &&NewDD);
     void ReadObjCDefinitionData(struct ObjCInterfaceDecl::DefinitionData &Data);
@@ -1969,7 +1971,8 @@ void ASTDeclReader::VisitUnresolvedUsingIfExistsDecl(
 
 void ASTDeclReader::ReadCXXDefinitionData(
     struct CXXRecordDecl::DefinitionData &Data, const CXXRecordDecl *D,
-    Decl *LambdaContext, unsigned IndexInLambdaContext) {
+    Decl *LambdaContext, unsigned IndexInLambdaContext,
+    Decl *LambdaInstantiatingContext) {
 
   BitsUnpacker CXXRecordDeclBits = Record.readInt();
 
@@ -2031,6 +2034,7 @@ void ASTDeclReader::ReadCXXDefinitionData(
       Reader.getContext().DeviceLambdaManglingNumbers[D] = DeviceManglingNumber;
     Lambda.IndexInContext = IndexInLambdaContext;
     Lambda.ContextDecl = LambdaContext;
+    Lambda.InstantiatingContextDecl = LambdaInstantiatingContext;
     Capture *ToCapture = nullptr;
     if (Lambda.NumCaptures) {
       ToCapture = (Capture *)Reader.getContext().Allocate(sizeof(Capture) *
@@ -2162,7 +2166,8 @@ void ASTDeclReader::MergeDefinitionData(
 
 void ASTDeclReader::ReadCXXRecordDefinition(CXXRecordDecl *D, bool Update,
                                             Decl *LambdaContext,
-                                            unsigned IndexInLambdaContext) {
+                                            unsigned IndexInLambdaContext,
+                                            Decl *LambdaInstantiatingContext) {
   struct CXXRecordDecl::DefinitionData *DD;
   ASTContext &C = Reader.getContext();
 
@@ -2184,7 +2189,8 @@ void ASTDeclReader::ReadCXXRecordDefinition(CXXRecordDecl *D, bool Update,
   if (!Canon->DefinitionData)
     Canon->DefinitionData = DD;
   D->DefinitionData = Canon->DefinitionData;
-  ReadCXXDefinitionData(*DD, D, LambdaContext, IndexInLambdaContext);
+  ReadCXXDefinitionData(*DD, D, LambdaContext, IndexInLambdaContext,
+                        LambdaInstantiatingContext);
 
   // We might already have a different definition for this record. This can
   // happen either because we're reading an update record, or because we've
@@ -2219,6 +2225,7 @@ ASTDeclReader::VisitCXXRecordDeclImpl(CXXRecordDecl *D) {
 
   Decl *LambdaContext = nullptr;
   unsigned IndexInLambdaContext = 0;
+  Decl *LambdaInstantiatingContext = nullptr;
 
   switch ((CXXRecKind)Record.readInt()) {
   case CXXRecNotTemplate:
@@ -2255,6 +2262,7 @@ ASTDeclReader::VisitCXXRecordDeclImpl(CXXRecordDecl *D) {
     LambdaContext = readDecl();
     if (LambdaContext)
       IndexInLambdaContext = Record.readInt();
+    LambdaInstantiatingContext = readDecl();
     mergeLambda(D, Redecl, LambdaContext, IndexInLambdaContext);
     break;
   }
@@ -2263,7 +2271,7 @@ ASTDeclReader::VisitCXXRecordDeclImpl(CXXRecordDecl *D) {
   bool WasDefinition = Record.readInt();
   if (WasDefinition)
     ReadCXXRecordDefinition(D, /*Update=*/false, LambdaContext,
-                            IndexInLambdaContext);
+                            IndexInLambdaContext, LambdaInstantiatingContext);
   else
     // Propagate DefinitionData pointer from the canonical declaration.
     D->DefinitionData = D->getCanonicalDecl()->DefinitionData;
diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp
index f224075643e998..2f9e033040d5f9 100644
--- a/clang/lib/Serialization/ASTWriterDecl.cpp
+++ b/clang/lib/Serialization/ASTWriterDecl.cpp
@@ -1479,6 +1479,7 @@ void ASTDeclWriter::VisitCXXRecordDecl(CXXRecordDecl *D) {
     } else {
       Record.push_back(0);
     }
+    Record.AddDeclRef(D->getLambdaInstantiatingContextDecl());
   } else {
     Record.push_back(CXXRecNotTemplate);
   }



More information about the cfe-commits mailing list