ahatanak created this revision.
ahatanak added reviewers: tahonermann, erichkeane, aaron.ballman, shafik, 
Bigcheese, arphaman.
ahatanak added a project: clang.
Herald added a project: All.
ahatanak requested review of this revision.

This is needed to fix https://github.com/llvm/llvm-project/issues/60155.

An assertion in `tryCaptureVariable` fails because `SubstDefaultArgument` 
pushes the context for the lambda's function operator, but the LambdaScopeInfo 
isn't being pushed to the stack.

It appears that the assertion started to fail in 
4409a83c293537e22da046b54e9f69454cdd3dca 
<https://reviews.llvm.org/rG4409a83c293537e22da046b54e9f69454cdd3dca>, which 
delays instantiation of default arguments. By the time the default arguments 
are instantiated, which happens after `inherited::TransformLambdaExpr` is 
called, the lambda scope has already been popped.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D143109

Files:
  clang/lib/Sema/SemaTemplateInstantiate.cpp
  clang/test/SemaCXX/lambda-default-arg.cpp


Index: clang/test/SemaCXX/lambda-default-arg.cpp
===================================================================
--- /dev/null
+++ clang/test/SemaCXX/lambda-default-arg.cpp
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -std=c++17 -verify -fsyntax-only %s
+
+template <class T> bool test0() {
+  constexpr float a = 1e-5f;
+  return [=](float b = a) -> bool {
+    return a < 0;
+  }();
+}
+
+bool b0 = test0<int>();
+
+template <class T> bool test1() {
+  float a = 1e-5f;
+  return [=](float b = a) -> bool { // expected-error {{default argument 
references local variable 'a'}}
+    return a < 0;
+  }();
+}
+
+bool b1 = test1<int>();
Index: clang/lib/Sema/SemaTemplateInstantiate.cpp
===================================================================
--- clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -1348,6 +1348,13 @@
         Expr *UninstExpr = PVD->getUninstantiatedDefaultArg();
         // FIXME: Obtain the source location for the '=' token.
         SourceLocation EqualLoc = UninstExpr->getBeginLoc();
+
+        // Push an empty lambda scope. This is needed as SubstDefaultArgument
+        // pushes the context for the lambda's function call operator and we
+        // need to keep the contexts and the function scopes in sync.
+        getSema().PushLambdaScope();
+        Sema::FunctionScopeRAII FuncScopeCleanup(getSema());
+
         if (SemaRef.SubstDefaultArgument(EqualLoc, PVD, TemplateArgs)) {
           // If substitution fails, the default argument is set to a
           // RecoveryExpr that wraps the uninstantiated default argument so


Index: clang/test/SemaCXX/lambda-default-arg.cpp
===================================================================
--- /dev/null
+++ clang/test/SemaCXX/lambda-default-arg.cpp
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -std=c++17 -verify -fsyntax-only %s
+
+template <class T> bool test0() {
+  constexpr float a = 1e-5f;
+  return [=](float b = a) -> bool {
+    return a < 0;
+  }();
+}
+
+bool b0 = test0<int>();
+
+template <class T> bool test1() {
+  float a = 1e-5f;
+  return [=](float b = a) -> bool { // expected-error {{default argument references local variable 'a'}}
+    return a < 0;
+  }();
+}
+
+bool b1 = test1<int>();
Index: clang/lib/Sema/SemaTemplateInstantiate.cpp
===================================================================
--- clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -1348,6 +1348,13 @@
         Expr *UninstExpr = PVD->getUninstantiatedDefaultArg();
         // FIXME: Obtain the source location for the '=' token.
         SourceLocation EqualLoc = UninstExpr->getBeginLoc();
+
+        // Push an empty lambda scope. This is needed as SubstDefaultArgument
+        // pushes the context for the lambda's function call operator and we
+        // need to keep the contexts and the function scopes in sync.
+        getSema().PushLambdaScope();
+        Sema::FunctionScopeRAII FuncScopeCleanup(getSema());
+
         if (SemaRef.SubstDefaultArgument(EqualLoc, PVD, TemplateArgs)) {
           // If substitution fails, the default argument is set to a
           // RecoveryExpr that wraps the uninstantiated default argument so
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to