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

Younan Zhang via cfe-commits cfe-commits at lists.llvm.org
Fri Feb 9 23:35:02 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] 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;



More information about the cfe-commits mailing list