[clang] f0c7505 - [Clang] Fix the order of addInstantiatedParameters in LambdaScopeForCallOperatorInstantiationRAII (#97215)

via cfe-commits cfe-commits at lists.llvm.org
Tue Jul 9 01:39:53 PDT 2024


Author: Yupei Liu
Date: 2024-07-09T16:39:50+08:00
New Revision: f0c7505f597998c84023ccd609ecfc9af3d5b4d6

URL: https://github.com/llvm/llvm-project/commit/f0c7505f597998c84023ccd609ecfc9af3d5b4d6
DIFF: https://github.com/llvm/llvm-project/commit/f0c7505f597998c84023ccd609ecfc9af3d5b4d6.diff

LOG: [Clang] Fix the order of addInstantiatedParameters in LambdaScopeForCallOperatorInstantiationRAII (#97215)

Currently, `addInstantiatedParameters` is called from the innermost
lambda outward. However, when the function parameters of an inner lambda
depend on the function parameters of an outer lambda, it can lead to a
crash due to the inability to find a mapping for the instantiated decl.

This PR corrects this behavior by calling `addInstantiatedParameters`
from the outside in.

repro code: https://godbolt.org/z/KbsxWesW6

```cpp
namespace dependent_param_concept {
template <typename... Ts> void sink(Ts...) {}
void dependent_param() {
  auto L = [](auto... x) {
    return [](decltype(x)... y) { // `y` depends on `x`
      return [](int z)
        requires requires { sink(y..., z); }
      {};
    };
  };
  L(0, 1)(1, 2)(1);
}
} // namespace dependent_param_concept
```

This PR is a prerequisite for implmenting #61426

Added: 
    

Modified: 
    clang/docs/ReleaseNotes.rst
    clang/lib/Sema/SemaLambda.cpp
    clang/test/SemaTemplate/concepts-lambda.cpp

Removed: 
    


################################################################################
diff  --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 795712eac1052..e3ed18e1b288a 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -962,6 +962,7 @@ Bug Fixes to C++ Support
 - Fix a crash caused by improper use of ``__array_extent``. (#GH80474)
 - Fixed several bugs in capturing variables within unevaluated contexts. (#GH63845), (#GH67260), (#GH69307),
   (#GH88081), (#GH89496), (#GH90669) and (#GH91633).
+- Fixed a crash in constraint instantiation under nested lambdas with dependent parameters.
 - Fixed handling of brace ellison when building deduction guides. (#GH64625), (#GH83368).
 - Clang now instantiates local constexpr functions eagerly for constant evaluators. (#GH35052), (#GH94849)
 - Fixed a failed assertion when attempting to convert an integer representing the 
diff erence

diff  --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp
index 56818042952a6..4b19296e8a23a 100644
--- a/clang/lib/Sema/SemaLambda.cpp
+++ b/clang/lib/Sema/SemaLambda.cpp
@@ -2383,23 +2383,37 @@ Sema::LambdaScopeForCallOperatorInstantiationRAII::
 
   SemaRef.RebuildLambdaScopeInfo(cast<CXXMethodDecl>(FD));
 
-  FunctionDecl *Pattern = getPatternFunctionDecl(FD);
-  if (Pattern) {
-    SemaRef.addInstantiatedCapturesToScope(FD, Pattern, Scope, MLTAL);
+  FunctionDecl *FDPattern = getPatternFunctionDecl(FD);
+  if (!FDPattern)
+    return;
 
-    FunctionDecl *ParentFD = FD;
-    while (ShouldAddDeclsFromParentScope) {
+  SemaRef.addInstantiatedCapturesToScope(FD, FDPattern, Scope, MLTAL);
 
-      ParentFD =
-          dyn_cast<FunctionDecl>(getLambdaAwareParentOfDeclContext(ParentFD));
-      Pattern =
-          dyn_cast<FunctionDecl>(getLambdaAwareParentOfDeclContext(Pattern));
+  if (!ShouldAddDeclsFromParentScope)
+    return;
 
-      if (!ParentFD || !Pattern)
-        break;
+  llvm::SmallVector<std::pair<FunctionDecl *, FunctionDecl *>, 4>
+      ParentInstantiations;
+  while (true) {
+    FDPattern =
+        dyn_cast<FunctionDecl>(getLambdaAwareParentOfDeclContext(FDPattern));
+    FD = dyn_cast<FunctionDecl>(getLambdaAwareParentOfDeclContext(FD));
 
-      SemaRef.addInstantiatedParametersToScope(ParentFD, Pattern, Scope, MLTAL);
-      SemaRef.addInstantiatedLocalVarsToScope(ParentFD, Pattern, Scope);
-    }
+    if (!FDPattern || !FD)
+      break;
+
+    ParentInstantiations.emplace_back(FDPattern, FD);
+  }
+
+  // Add instantiated parameters and local vars to scopes, starting from the
+  // outermost lambda to the innermost lambda. This ordering ensures that
+  // parameters in inner lambdas can correctly depend on those defined
+  // in outer lambdas, e.g. auto L = [](auto... x) {
+  //   return [](decltype(x)... y) { }; // `y` depends on `x`
+  // };
+
+  for (const auto &[FDPattern, FD] : llvm::reverse(ParentInstantiations)) {
+    SemaRef.addInstantiatedParametersToScope(FD, FDPattern, Scope, MLTAL);
+    SemaRef.addInstantiatedLocalVarsToScope(FD, FDPattern, Scope);
   }
 }

diff  --git a/clang/test/SemaTemplate/concepts-lambda.cpp b/clang/test/SemaTemplate/concepts-lambda.cpp
index 280be71284f97..252ef08549a48 100644
--- a/clang/test/SemaTemplate/concepts-lambda.cpp
+++ b/clang/test/SemaTemplate/concepts-lambda.cpp
@@ -237,3 +237,17 @@ concept D = []<C T = int>() { return true; }();
 D auto x = 0;
 
 } // namespace GH93821
+
+namespace dependent_param_concept {
+template <typename... Ts> void sink(Ts...) {}
+void dependent_param() {
+  auto L = [](auto... x) {
+    return [](decltype(x)... y) {
+      return [](int z)
+        requires requires { sink(y..., z); }
+      {};
+    };
+  };
+  L(0, 1)(1, 2)(1);
+}
+} // namespace dependent_param_concept


        


More information about the cfe-commits mailing list