[clang] [clang][Sema] Fix a bug when instantiating a lambda with requires clause (PR #65193)

via cfe-commits cfe-commits at lists.llvm.org
Tue Oct 3 03:35:18 PDT 2023


https://github.com/0x59616e updated https://github.com/llvm/llvm-project/pull/65193

>From 8abb437d97382f517bcbf0b5c4a542172c5ae144 Mon Sep 17 00:00:00 2001
From: Sheng <ox59616e at gmail.com>
Date: Wed, 30 Aug 2023 11:44:23 +0800
Subject: [PATCH 1/6] [clang][Sema] Fix a bug when instantiating a lambda with
 requires clause

Instantiating a lambda at a scope different from its definition
scope will paralyze clang if the trailing require clause
refers to local variables of that definition scope.

This patch fixes this by re-adding the local variables to
`LocalInstantiationScope`.

Fixes #64462
---
 clang/lib/Sema/SemaConcept.cpp | 59 ++++++++++++++++++++++++++++++++++
 clang/test/SemaCXX/pr64462.cpp | 20 ++++++++++++
 2 files changed, 79 insertions(+)
 create mode 100644 clang/test/SemaCXX/pr64462.cpp

diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index 036548b68247bfa..41af513969c6615 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -584,6 +584,58 @@ bool Sema::addInstantiatedCapturesToScope(
   return false;
 }
 
+static void addDeclsFromParentScope(Sema &S, FunctionDecl *FD,
+                                    LocalInstantiationScope &Scope) {
+  assert(isLambdaCallOperator(FD) && "FD must be a lambda call operator");
+
+  LambdaScopeInfo *LSI = cast<LambdaScopeInfo>(S.getFunctionScopes().back());
+
+  auto captureVar = [&](VarDecl *VD) {
+    LSI->addCapture(VD, /*isBlock=*/false, /*isByref=*/false,
+                    /*isNested=*/false, VD->getBeginLoc(), SourceLocation(),
+                    VD->getType(), /*Invalid=*/false);
+  };
+
+  FD = dyn_cast<FunctionDecl>(FD->getParent()->getParent());
+
+  if (!FD || !FD->isTemplateInstantiation())
+    return;
+
+  FunctionDecl *Pattern = FD->getPrimaryTemplate()->getTemplatedDecl();
+
+  for (unsigned I = 0; I < Pattern->getNumParams(); ++I) {
+    ParmVarDecl *PVD = Pattern->getParamDecl(I);
+    if (!PVD->isParameterPack()) {
+      Scope.InstantiatedLocal(PVD, FD->getParamDecl(I));
+      captureVar(FD->getParamDecl(I));
+      continue;
+    }
+
+    Scope.MakeInstantiatedLocalArgPack(PVD);
+
+    for (ParmVarDecl *Inst : FD->parameters().drop_front(I)) {
+      Scope.InstantiatedLocalPackArg(PVD, Inst);
+      captureVar(Inst);
+    }
+  }
+
+  for (auto *decl : Pattern->decls()) {
+    if (!isa<VarDecl>(decl) || isa<ParmVarDecl>(decl))
+      continue;
+
+    IdentifierInfo *II = cast<NamedDecl>(decl)->getIdentifier();
+    auto it = llvm::find_if(FD->decls(), [&](Decl *inst) {
+      VarDecl *VD = dyn_cast<VarDecl>(inst);
+      return VD && VD->isLocalVarDecl() && VD->getIdentifier() == II;
+    });
+
+    assert(it != FD->decls().end() && "Cannot find the instantiated variable.");
+
+    Scope.InstantiatedLocal(decl, *it);
+    captureVar(cast<VarDecl>(*it));
+  }
+}
+
 bool Sema::SetupConstraintScope(
     FunctionDecl *FD, std::optional<ArrayRef<TemplateArgument>> TemplateArgs,
     MultiLevelTemplateArgumentList MLTAL, LocalInstantiationScope &Scope) {
@@ -701,6 +753,7 @@ bool Sema::CheckFunctionConstraints(const FunctionDecl *FD,
       CtxToSave = CtxToSave->getNonTransparentContext();
   }
 
+  const bool shouldAddDeclsFromParentScope = !CtxToSave->Encloses(CurContext);
   ContextRAII SavedContext{*this, CtxToSave};
   LocalInstantiationScope Scope(*this, !ForOverloadResolution ||
                                            isLambdaCallOperator(FD));
@@ -722,6 +775,9 @@ bool Sema::CheckFunctionConstraints(const FunctionDecl *FD,
   LambdaScopeForCallOperatorInstantiationRAII LambdaScope(
       *this, const_cast<FunctionDecl *>(FD), *MLTAL, Scope);
 
+  if (isLambdaCallOperator(FD) && shouldAddDeclsFromParentScope)
+    addDeclsFromParentScope(*this, const_cast<FunctionDecl *>(FD), Scope);
+
   return CheckConstraintSatisfaction(
       FD, {FD->getTrailingRequiresClause()}, *MLTAL,
       SourceRange(UsageLoc.isValid() ? UsageLoc : FD->getLocation()),
@@ -913,6 +969,9 @@ bool Sema::CheckInstantiatedFunctionTemplateConstraints(
   LambdaScopeForCallOperatorInstantiationRAII LambdaScope(
       *this, const_cast<FunctionDecl *>(Decl), *MLTAL, Scope);
 
+  if (isLambdaCallOperator(Decl))
+    addDeclsFromParentScope(*this, Decl, Scope);
+
   llvm::SmallVector<Expr *, 1> Converted;
   return CheckConstraintSatisfaction(Template, TemplateAC, Converted, *MLTAL,
                                      PointOfInstantiation, Satisfaction);
diff --git a/clang/test/SemaCXX/pr64462.cpp b/clang/test/SemaCXX/pr64462.cpp
new file mode 100644
index 000000000000000..cc8b5510d1a823a
--- /dev/null
+++ b/clang/test/SemaCXX/pr64462.cpp
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -verify -std=c++20 -fsyntax-only %s
+
+auto c1(auto f, auto ...fs) {
+  constexpr bool a = true;
+  // expected-note at +2{{because substituted constraint expression is ill-formed: no matching function for call to 'c1'}}
+  // expected-note at +1{{candidate template ignored: constraints not satisfied [with auto:1 = bool}}
+  return [](auto) requires a && (c1(fs...)) {};
+}
+
+auto c2(auto f, auto ...fs) {
+  constexpr bool a = true;
+  // expected-note at +2{{because substituted constraint expression is ill-formed: no matching function for call to 'c2'}}
+  // expected-note at +1{{candidate function not viable: constraints not satisfied}}
+  return []() requires a && (c2(fs...)) {};
+}
+
+void foo() {
+  c1(true)(true); // expected-error {{no matching function for call to object of type}}
+  c2(true)(); // expected-error {{no matching function for call to object of type}}
+}

>From e391ab7b2b3bc3aeffd38b5ac7f6c7c2a2e5fc04 Mon Sep 17 00:00:00 2001
From: Sheng <ox59616e at gmail.com>
Date: Fri, 15 Sep 2023 02:02:34 +0800
Subject: [PATCH 2/6] Add support for nested lambda.

---
 clang/lib/Sema/SemaConcept.cpp | 78 ++++++++++++++++++++--------------
 clang/test/SemaCXX/pr64462.cpp | 25 +++++------
 2 files changed, 59 insertions(+), 44 deletions(-)

diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index 41af513969c6615..fc2ddad4e76eeec 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -584,6 +584,20 @@ bool Sema::addInstantiatedCapturesToScope(
   return false;
 }
 
+static FunctionDecl *getPatternFunctionDecl(FunctionDecl *FD) {
+  if (FD->getTemplatedKind() == FunctionDecl::TK_MemberSpecialization) {
+    while (FD->getInstantiatedFromMemberFunction())
+      FD = FD->getInstantiatedFromMemberFunction();
+    return FD;
+  }
+
+  FunctionTemplateDecl *FTD = FD->getPrimaryTemplate();
+  while (FTD->getInstantiatedFromMemberTemplate())
+    FTD = FTD->getInstantiatedFromMemberTemplate();
+
+  return FTD->getTemplatedDecl();
+}
+
 static void addDeclsFromParentScope(Sema &S, FunctionDecl *FD,
                                     LocalInstantiationScope &Scope) {
   assert(isLambdaCallOperator(FD) && "FD must be a lambda call operator");
@@ -596,43 +610,45 @@ static void addDeclsFromParentScope(Sema &S, FunctionDecl *FD,
                     VD->getType(), /*Invalid=*/false);
   };
 
-  FD = dyn_cast<FunctionDecl>(FD->getParent()->getParent());
-
-  if (!FD || !FD->isTemplateInstantiation())
-    return;
+  while (true) {
+    FD = dyn_cast_or_null<FunctionDecl>(FD->getParent()->getParent());
+    if (!FD || !FD->isTemplateInstantiation())
+      return;
 
-  FunctionDecl *Pattern = FD->getPrimaryTemplate()->getTemplatedDecl();
+    FunctionDecl *Pattern = getPatternFunctionDecl(FD);
 
-  for (unsigned I = 0; I < Pattern->getNumParams(); ++I) {
-    ParmVarDecl *PVD = Pattern->getParamDecl(I);
-    if (!PVD->isParameterPack()) {
-      Scope.InstantiatedLocal(PVD, FD->getParamDecl(I));
-      captureVar(FD->getParamDecl(I));
-      continue;
-    }
+    for (unsigned I = 0; I < Pattern->getNumParams(); ++I) {
+      ParmVarDecl *PVD = Pattern->getParamDecl(I);
+      if (!PVD->isParameterPack()) {
+        Scope.InstantiatedLocal(PVD, FD->getParamDecl(I));
+        captureVar(FD->getParamDecl(I));
+        continue;
+      }
 
-    Scope.MakeInstantiatedLocalArgPack(PVD);
+      Scope.MakeInstantiatedLocalArgPack(PVD);
 
-    for (ParmVarDecl *Inst : FD->parameters().drop_front(I)) {
-      Scope.InstantiatedLocalPackArg(PVD, Inst);
-      captureVar(Inst);
+      for (ParmVarDecl *Inst : FD->parameters().drop_front(I)) {
+        Scope.InstantiatedLocalPackArg(PVD, Inst);
+        captureVar(Inst);
+      }
     }
-  }
 
-  for (auto *decl : Pattern->decls()) {
-    if (!isa<VarDecl>(decl) || isa<ParmVarDecl>(decl))
-      continue;
+    for (auto *decl : Pattern->decls()) {
+      if (!isa<VarDecl>(decl) || isa<ParmVarDecl>(decl))
+        continue;
 
-    IdentifierInfo *II = cast<NamedDecl>(decl)->getIdentifier();
-    auto it = llvm::find_if(FD->decls(), [&](Decl *inst) {
-      VarDecl *VD = dyn_cast<VarDecl>(inst);
-      return VD && VD->isLocalVarDecl() && VD->getIdentifier() == II;
-    });
+      IdentifierInfo *II = cast<NamedDecl>(decl)->getIdentifier();
+      auto it = llvm::find_if(FD->decls(), [&](Decl *inst) {
+        VarDecl *VD = dyn_cast<VarDecl>(inst);
+        return VD && VD->isLocalVarDecl() && VD->getIdentifier() == II;
+      });
 
-    assert(it != FD->decls().end() && "Cannot find the instantiated variable.");
+      if (it == FD->decls().end())
+        continue;
 
-    Scope.InstantiatedLocal(decl, *it);
-    captureVar(cast<VarDecl>(*it));
+      Scope.InstantiatedLocal(decl, *it);
+      captureVar(cast<VarDecl>(*it));
+    }
   }
 }
 
@@ -753,10 +769,8 @@ bool Sema::CheckFunctionConstraints(const FunctionDecl *FD,
       CtxToSave = CtxToSave->getNonTransparentContext();
   }
 
-  const bool shouldAddDeclsFromParentScope = !CtxToSave->Encloses(CurContext);
   ContextRAII SavedContext{*this, CtxToSave};
-  LocalInstantiationScope Scope(*this, !ForOverloadResolution ||
-                                           isLambdaCallOperator(FD));
+  LocalInstantiationScope Scope(*this, !ForOverloadResolution);
   std::optional<MultiLevelTemplateArgumentList> MLTAL =
       SetupConstraintCheckingTemplateArgumentsAndScope(
           const_cast<FunctionDecl *>(FD), {}, Scope);
@@ -775,7 +789,7 @@ bool Sema::CheckFunctionConstraints(const FunctionDecl *FD,
   LambdaScopeForCallOperatorInstantiationRAII LambdaScope(
       *this, const_cast<FunctionDecl *>(FD), *MLTAL, Scope);
 
-  if (isLambdaCallOperator(FD) && shouldAddDeclsFromParentScope)
+  if (isLambdaCallOperator(FD) && ForOverloadResolution)
     addDeclsFromParentScope(*this, const_cast<FunctionDecl *>(FD), Scope);
 
   return CheckConstraintSatisfaction(
diff --git a/clang/test/SemaCXX/pr64462.cpp b/clang/test/SemaCXX/pr64462.cpp
index cc8b5510d1a823a..7cffb3583dcd408 100644
--- a/clang/test/SemaCXX/pr64462.cpp
+++ b/clang/test/SemaCXX/pr64462.cpp
@@ -2,19 +2,20 @@
 
 auto c1(auto f, auto ...fs) {
   constexpr bool a = true;
-  // expected-note at +2{{because substituted constraint expression is ill-formed: no matching function for call to 'c1'}}
-  // expected-note at +1{{candidate template ignored: constraints not satisfied [with auto:1 = bool}}
-  return [](auto) requires a && (c1(fs...)) {};
-}
-
-auto c2(auto f, auto ...fs) {
-  constexpr bool a = true;
-  // expected-note at +2{{because substituted constraint expression is ill-formed: no matching function for call to 'c2'}}
-  // expected-note at +1{{candidate function not viable: constraints not satisfied}}
-  return []() requires a && (c2(fs...)) {};
+  return [](auto) requires a {
+    constexpr bool b = true;
+    return []() requires a && b {
+      constexpr bool c = true;
+      return [](auto) requires a && b && c {
+        constexpr bool d = true;
+        // expected-note at +2{{because substituted constraint expression is ill-formed: no matching function for call to 'c1'}}
+        // expected-note at +1{{candidate function not viable: constraints not satisfied}}
+        return []() requires a && b && c && d && (c1(fs...)) {};
+      };
+    }();
+  }(1);
 }
 
 void foo() {
-  c1(true)(true); // expected-error {{no matching function for call to object of type}}
-  c2(true)(); // expected-error {{no matching function for call to object of type}}
+  c1(true)(1.0)(); // expected-error{{no matching function for call to object of type}}
 }

>From 7edb6a53c0ed412a097367f120b62bdbb2dbf535 Mon Sep 17 00:00:00 2001
From: Sheng <ox59616e at gmail.com>
Date: Sat, 16 Sep 2023 09:36:08 +0800
Subject: [PATCH 3/6] Move the implementation into
 LambdaScopeForCallOperatorInstantiationRAII

---
 clang/include/clang/Sema/Sema.h               |  8 +-
 clang/lib/Sema/SemaConcept.cpp                | 77 +------------------
 clang/lib/Sema/SemaLambda.cpp                 | 62 ++++++++++-----
 .../lib/Sema/SemaTemplateInstantiateDecl.cpp  | 30 ++++++++
 4 files changed, 81 insertions(+), 96 deletions(-)

diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 5bef0335f7891c9..b19481182a8a9fc 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -7383,7 +7383,8 @@ class Sema final {
   public:
     LambdaScopeForCallOperatorInstantiationRAII(
         Sema &SemasRef, FunctionDecl *FD, MultiLevelTemplateArgumentList MLTAL,
-        LocalInstantiationScope &Scope);
+        LocalInstantiationScope &Scope,
+        bool shouldAddDeclsFromParentScope = true);
   };
 
   /// Check whether the given expression is a valid constraint expression.
@@ -7409,6 +7410,11 @@ class Sema final {
   llvm::ContextualFoldingSet<ConstraintSatisfaction, const ASTContext &>
       SatisfactionCache;
 
+  /// Intorduce the instantiated local variables into the local
+  /// instantiation scope.
+  void addInstantiatedLocalVarsToScope(FunctionDecl *Function,
+                                       const FunctionDecl *PatternDecl,
+                                       LocalInstantiationScope &Scope);
   /// Introduce the instantiated function parameters into the local
   /// instantiation scope, and set the parameter names to those used
   /// in the template.
diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index fc2ddad4e76eeec..0ef03293b46ffb7 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -584,74 +584,6 @@ bool Sema::addInstantiatedCapturesToScope(
   return false;
 }
 
-static FunctionDecl *getPatternFunctionDecl(FunctionDecl *FD) {
-  if (FD->getTemplatedKind() == FunctionDecl::TK_MemberSpecialization) {
-    while (FD->getInstantiatedFromMemberFunction())
-      FD = FD->getInstantiatedFromMemberFunction();
-    return FD;
-  }
-
-  FunctionTemplateDecl *FTD = FD->getPrimaryTemplate();
-  while (FTD->getInstantiatedFromMemberTemplate())
-    FTD = FTD->getInstantiatedFromMemberTemplate();
-
-  return FTD->getTemplatedDecl();
-}
-
-static void addDeclsFromParentScope(Sema &S, FunctionDecl *FD,
-                                    LocalInstantiationScope &Scope) {
-  assert(isLambdaCallOperator(FD) && "FD must be a lambda call operator");
-
-  LambdaScopeInfo *LSI = cast<LambdaScopeInfo>(S.getFunctionScopes().back());
-
-  auto captureVar = [&](VarDecl *VD) {
-    LSI->addCapture(VD, /*isBlock=*/false, /*isByref=*/false,
-                    /*isNested=*/false, VD->getBeginLoc(), SourceLocation(),
-                    VD->getType(), /*Invalid=*/false);
-  };
-
-  while (true) {
-    FD = dyn_cast_or_null<FunctionDecl>(FD->getParent()->getParent());
-    if (!FD || !FD->isTemplateInstantiation())
-      return;
-
-    FunctionDecl *Pattern = getPatternFunctionDecl(FD);
-
-    for (unsigned I = 0; I < Pattern->getNumParams(); ++I) {
-      ParmVarDecl *PVD = Pattern->getParamDecl(I);
-      if (!PVD->isParameterPack()) {
-        Scope.InstantiatedLocal(PVD, FD->getParamDecl(I));
-        captureVar(FD->getParamDecl(I));
-        continue;
-      }
-
-      Scope.MakeInstantiatedLocalArgPack(PVD);
-
-      for (ParmVarDecl *Inst : FD->parameters().drop_front(I)) {
-        Scope.InstantiatedLocalPackArg(PVD, Inst);
-        captureVar(Inst);
-      }
-    }
-
-    for (auto *decl : Pattern->decls()) {
-      if (!isa<VarDecl>(decl) || isa<ParmVarDecl>(decl))
-        continue;
-
-      IdentifierInfo *II = cast<NamedDecl>(decl)->getIdentifier();
-      auto it = llvm::find_if(FD->decls(), [&](Decl *inst) {
-        VarDecl *VD = dyn_cast<VarDecl>(inst);
-        return VD && VD->isLocalVarDecl() && VD->getIdentifier() == II;
-      });
-
-      if (it == FD->decls().end())
-        continue;
-
-      Scope.InstantiatedLocal(decl, *it);
-      captureVar(cast<VarDecl>(*it));
-    }
-  }
-}
-
 bool Sema::SetupConstraintScope(
     FunctionDecl *FD, std::optional<ArrayRef<TemplateArgument>> TemplateArgs,
     MultiLevelTemplateArgumentList MLTAL, LocalInstantiationScope &Scope) {
@@ -787,10 +719,8 @@ bool Sema::CheckFunctionConstraints(const FunctionDecl *FD,
   CXXThisScopeRAII ThisScope(*this, Record, ThisQuals, Record != nullptr);
 
   LambdaScopeForCallOperatorInstantiationRAII LambdaScope(
-      *this, const_cast<FunctionDecl *>(FD), *MLTAL, Scope);
-
-  if (isLambdaCallOperator(FD) && ForOverloadResolution)
-    addDeclsFromParentScope(*this, const_cast<FunctionDecl *>(FD), Scope);
+      *this, const_cast<FunctionDecl *>(FD), *MLTAL, Scope,
+      ForOverloadResolution);
 
   return CheckConstraintSatisfaction(
       FD, {FD->getTrailingRequiresClause()}, *MLTAL,
@@ -983,9 +913,6 @@ bool Sema::CheckInstantiatedFunctionTemplateConstraints(
   LambdaScopeForCallOperatorInstantiationRAII LambdaScope(
       *this, const_cast<FunctionDecl *>(Decl), *MLTAL, Scope);
 
-  if (isLambdaCallOperator(Decl))
-    addDeclsFromParentScope(*this, Decl, Scope);
-
   llvm::SmallVector<Expr *, 1> Converted;
   return CheckConstraintSatisfaction(Template, TemplateAC, Converted, *MLTAL,
                                      PointOfInstantiation, Satisfaction);
diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp
index 6fd91bda61af5a7..98449c95d6bea32 100644
--- a/clang/lib/Sema/SemaLambda.cpp
+++ b/clang/lib/Sema/SemaLambda.cpp
@@ -2296,33 +2296,55 @@ ExprResult Sema::BuildBlockForLambdaConversion(SourceLocation CurrentLocation,
   return BuildBlock;
 }
 
+static FunctionDecl *getPatternFunctionDecl(FunctionDecl *FD) {
+  if (FD->getTemplatedKind() == FunctionDecl::TK_MemberSpecialization) {
+    while (FD->getInstantiatedFromMemberFunction())
+      FD = FD->getInstantiatedFromMemberFunction();
+    return FD;
+  }
+
+  if (FD->getTemplatedKind() == FunctionDecl::TK_DependentNonTemplate)
+    return FD->getInstantiatedFromDecl();
+
+  FunctionTemplateDecl *FTD = FD->getPrimaryTemplate();
+  if (!FTD)
+    return nullptr;
+
+  while (FTD->getInstantiatedFromMemberTemplate())
+    FTD = FTD->getInstantiatedFromMemberTemplate();
+
+  return FTD->getTemplatedDecl();
+}
+
 Sema::LambdaScopeForCallOperatorInstantiationRAII::
     LambdaScopeForCallOperatorInstantiationRAII(
-        Sema &SemasRef, FunctionDecl *FD, MultiLevelTemplateArgumentList MLTAL,
-        LocalInstantiationScope &Scope)
-    : FunctionScopeRAII(SemasRef) {
+        Sema &SemaRef, FunctionDecl *FD, MultiLevelTemplateArgumentList MLTAL,
+        LocalInstantiationScope &Scope, bool shouldAddDeclsFromParentScope)
+    : FunctionScopeRAII(SemaRef) {
   if (!isLambdaCallOperator(FD)) {
     FunctionScopeRAII::disable();
     return;
   }
 
-  if (FD->isTemplateInstantiation() && FD->getPrimaryTemplate()) {
-    FunctionTemplateDecl *PrimaryTemplate = FD->getPrimaryTemplate();
-    if (const auto *FromMemTempl =
-            PrimaryTemplate->getInstantiatedFromMemberTemplate()) {
-      SemasRef.addInstantiatedCapturesToScope(
-          FD, FromMemTempl->getTemplatedDecl(), Scope, MLTAL);
-    }
-  }
+  SemaRef.RebuildLambdaScopeInfo(cast<CXXMethodDecl>(FD));
 
-  else if (FD->getTemplatedKind() == FunctionDecl::TK_MemberSpecialization ||
-           FD->getTemplatedKind() == FunctionDecl::TK_DependentNonTemplate) {
-    FunctionDecl *InstantiatedFrom =
-        FD->getTemplatedKind() == FunctionDecl::TK_MemberSpecialization
-            ? FD->getInstantiatedFromMemberFunction()
-            : FD->getInstantiatedFromDecl();
-    SemasRef.addInstantiatedCapturesToScope(FD, InstantiatedFrom, Scope, MLTAL);
-  }
+  FunctionDecl *Pattern = getPatternFunctionDecl(FD);
+  if (Pattern) {
+    SemaRef.addInstantiatedCapturesToScope(FD, Pattern, Scope, MLTAL);
+
+    FunctionDecl *ParentFD = FD;
+    while (shouldAddDeclsFromParentScope) {
+
+      ParentFD =
+          dyn_cast<FunctionDecl>(getLambdaAwareParentOfDeclContext(ParentFD));
+      Pattern =
+          dyn_cast<FunctionDecl>(getLambdaAwareParentOfDeclContext(Pattern));
 
-  SemasRef.RebuildLambdaScopeInfo(cast<CXXMethodDecl>(FD));
+      if (!FD || !Pattern)
+        break;
+
+      SemaRef.addInstantiatedParametersToScope(ParentFD, Pattern, Scope, MLTAL);
+      SemaRef.addInstantiatedLocalVarsToScope(ParentFD, Pattern, Scope);
+    }
+  }
 }
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index e4974b168482b05..3aaf1dad59b240f 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -4523,6 +4523,36 @@ TemplateDeclInstantiator::SubstFunctionType(FunctionDecl *D,
   return NewTInfo;
 }
 
+/// Intorduce the instantiated local variables into the local
+/// instantiation scope.
+void Sema::addInstantiatedLocalVarsToScope(FunctionDecl *Function,
+                                           const FunctionDecl *PatternDecl,
+                                           LocalInstantiationScope &Scope) {
+  LambdaScopeInfo *LSI = cast<LambdaScopeInfo>(getFunctionScopes().back());
+
+  for (auto *decl : PatternDecl->decls()) {
+    if (!isa<VarDecl>(decl) || isa<ParmVarDecl>(decl))
+      continue;
+
+    VarDecl *VD = cast<VarDecl>(decl);
+    IdentifierInfo *II = VD->getIdentifier();
+
+    auto it = llvm::find_if(Function->decls(), [&](Decl *inst) {
+      VarDecl *InstVD = dyn_cast<VarDecl>(inst);
+      return InstVD && InstVD->isLocalVarDecl() &&
+             InstVD->getIdentifier() == II;
+    });
+
+    if (it == Function->decls().end())
+      continue;
+
+    Scope.InstantiatedLocal(VD, *it);
+    LSI->addCapture(cast<VarDecl>(*it), /*isBlock=*/false, /*isByref=*/false,
+                    /*isNested=*/false, VD->getLocation(), SourceLocation(),
+                    VD->getType(), /*Invalid=*/false);
+  }
+}
+
 /// Introduce the instantiated function parameters into the local
 /// instantiation scope, and set the parameter names to those used
 /// in the template.

>From 22a5a4ede4f48a3d94258aee8acbecdcc2557cc4 Mon Sep 17 00:00:00 2001
From: Sheng <ox59616e at gmail.com>
Date: Tue, 3 Oct 2023 18:25:06 +0800
Subject: [PATCH 4/6] Fix typo

---
 clang/include/clang/Sema/Sema.h                | 2 +-
 clang/lib/Sema/SemaTemplateInstantiateDecl.cpp | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index b19481182a8a9fc..bc5c100385823d9 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -7410,7 +7410,7 @@ class Sema final {
   llvm::ContextualFoldingSet<ConstraintSatisfaction, const ASTContext &>
       SatisfactionCache;
 
-  /// Intorduce the instantiated local variables into the local
+  /// Introduce the instantiated local variables into the local
   /// instantiation scope.
   void addInstantiatedLocalVarsToScope(FunctionDecl *Function,
                                        const FunctionDecl *PatternDecl,
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 3aaf1dad59b240f..0b2b775f19a0166 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -4523,7 +4523,7 @@ TemplateDeclInstantiator::SubstFunctionType(FunctionDecl *D,
   return NewTInfo;
 }
 
-/// Intorduce the instantiated local variables into the local
+/// Introduce the instantiated local variables into the local
 /// instantiation scope.
 void Sema::addInstantiatedLocalVarsToScope(FunctionDecl *Function,
                                            const FunctionDecl *PatternDecl,

>From 1eda43020f23a7458f91a9f82a4363ea6f80eb8a Mon Sep 17 00:00:00 2001
From: Sheng <ox59616e at gmail.com>
Date: Tue, 3 Oct 2023 18:25:40 +0800
Subject: [PATCH 5/6] Align the code style.

---
 clang/include/clang/Sema/Sema.h | 2 +-
 clang/lib/Sema/SemaLambda.cpp   | 4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index bc5c100385823d9..bb05c45391b5473 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -7384,7 +7384,7 @@ class Sema final {
     LambdaScopeForCallOperatorInstantiationRAII(
         Sema &SemasRef, FunctionDecl *FD, MultiLevelTemplateArgumentList MLTAL,
         LocalInstantiationScope &Scope,
-        bool shouldAddDeclsFromParentScope = true);
+        bool ShouldAddDeclsFromParentScope = true);
   };
 
   /// Check whether the given expression is a valid constraint expression.
diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp
index 98449c95d6bea32..421048aaff5c90c 100644
--- a/clang/lib/Sema/SemaLambda.cpp
+++ b/clang/lib/Sema/SemaLambda.cpp
@@ -2319,7 +2319,7 @@ static FunctionDecl *getPatternFunctionDecl(FunctionDecl *FD) {
 Sema::LambdaScopeForCallOperatorInstantiationRAII::
     LambdaScopeForCallOperatorInstantiationRAII(
         Sema &SemaRef, FunctionDecl *FD, MultiLevelTemplateArgumentList MLTAL,
-        LocalInstantiationScope &Scope, bool shouldAddDeclsFromParentScope)
+        LocalInstantiationScope &Scope, bool ShouldAddDeclsFromParentScope)
     : FunctionScopeRAII(SemaRef) {
   if (!isLambdaCallOperator(FD)) {
     FunctionScopeRAII::disable();
@@ -2333,7 +2333,7 @@ Sema::LambdaScopeForCallOperatorInstantiationRAII::
     SemaRef.addInstantiatedCapturesToScope(FD, Pattern, Scope, MLTAL);
 
     FunctionDecl *ParentFD = FD;
-    while (shouldAddDeclsFromParentScope) {
+    while (ShouldAddDeclsFromParentScope) {
 
       ParentFD =
           dyn_cast<FunctionDecl>(getLambdaAwareParentOfDeclContext(ParentFD));

>From 6fa1071e09bd69274ba0a69bbafd94d6635b2eb2 Mon Sep 17 00:00:00 2001
From: Sheng <ox59616e at gmail.com>
Date: Tue, 3 Oct 2023 18:34:11 +0800
Subject: [PATCH 6/6] Add description in 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 6be824771c583be..886d7f2ef6da69d 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -282,6 +282,8 @@ Bug Fixes in This Version
   Fixes (`#67603 <https://github.com/llvm/llvm-project/issues/67603>`_)
 - Fixes a crash caused by a multidimensional array being captured by a lambda
   (`#67722 <https://github.com/llvm/llvm-project/issues/67722>`_).
+- Fixes a crash when instantiating a lambda with requires clause.
+  (`#64462 <https://github.com/llvm/llvm-project/issues/64462>`_)
 
 Bug Fixes to Compiler Builtins
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^



More information about the cfe-commits mailing list