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

via cfe-commits cfe-commits at lists.llvm.org
Fri Sep 15 18:37:03 PDT 2023


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

>From 3eafb85ff74271456cba24ea5892dd5660c1d332 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/3] [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 d1fa8e7831225b7..e48e0f743927a17 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -567,6 +567,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) {
@@ -684,6 +736,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));
@@ -705,6 +758,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()),
@@ -896,6 +952,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 68912e0a88fc38cc5467c52f305e3c693f310dba 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/3] 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 e48e0f743927a17..dbe7a05660decf0 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -567,6 +567,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");
@@ -579,43 +593,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));
+    }
   }
 }
 
@@ -736,10 +752,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);
@@ -758,7 +772,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 1aff72f446c6febee0bce9ef3199a9c66bf16b75 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/3] 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 304108df9f8d029..bd72da0da2425b2 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -7370,7 +7370,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.
@@ -7396,6 +7397,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 dbe7a05660decf0..a0cf69cd8f1b57c 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -567,74 +567,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) {
@@ -770,10 +702,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,
@@ -966,9 +896,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 1702ddb3ee0fbf0..96d02c5a2f137ed 100644
--- a/clang/lib/Sema/SemaLambda.cpp
+++ b/clang/lib/Sema/SemaLambda.cpp
@@ -2256,33 +2256,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 37a7d6204413a38..eac599143ec9a0e 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -4515,6 +4515,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.



More information about the cfe-commits mailing list