Skip to content

Commit

Permalink
[Clang] Fix the order of addInstantiatedParameters in LambdaScopeForC…
Browse files Browse the repository at this point in the history
…allOperatorInstantiationRAII (#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
  • Loading branch information
LYP951018 authored Jul 9, 2024
1 parent e5865ec commit f0c7505
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 14 deletions.
1 change: 1 addition & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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 difference
Expand Down
42 changes: 28 additions & 14 deletions clang/lib/Sema/SemaLambda.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
14 changes: 14 additions & 0 deletions clang/test/SemaTemplate/concepts-lambda.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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

0 comments on commit f0c7505

Please sign in to comment.