From 73bd7cd7e4f9bf99bcc1bea87038f1266cdda548 Mon Sep 17 00:00:00 2001 From: James Dennett Date: Thu, 7 May 2015 18:48:18 +0000 Subject: [PATCH] Replace the broken LambdaCapture::isInitCapture API. A LambdaCapture does not have sufficient information to correctly determine whether it is an init-capture or not. Doing so requires knowledge held in the LambdaExpr itself. It the case of a nested capture of an init-capture it is not sufficient to check (as LambdaCapture::isInitCapture did) whether the associated VarDecl was from an init-capture. This patch moves isInitCapture to LambdaExpr and updates Capture->isInitCapture() to Lambda->isInitCapture(Capture). git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@236760 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/DataRecursiveASTVisitor.h | 2 +- include/clang/AST/ExprCXX.h | 3 +++ include/clang/AST/LambdaCapture.h | 5 ----- include/clang/AST/RecursiveASTVisitor.h | 2 +- lib/AST/ExprCXX.cpp | 5 +++++ lib/AST/StmtPrinter.cpp | 4 ++-- lib/Sema/TreeTransform.h | 4 ++-- test/SemaCXX/cxx1y-init-captures.cpp | 25 ++++++++++++++++++++- 8 files changed, 38 insertions(+), 12 deletions(-) diff --git a/include/clang/AST/DataRecursiveASTVisitor.h b/include/clang/AST/DataRecursiveASTVisitor.h index d3dde6803f..9b5b0233bb 100644 --- a/include/clang/AST/DataRecursiveASTVisitor.h +++ b/include/clang/AST/DataRecursiveASTVisitor.h @@ -791,7 +791,7 @@ template bool RecursiveASTVisitor::TraverseLambdaCapture(LambdaExpr *LE, const LambdaCapture *C) { - if (C->isInitCapture()) + if (LE->isInitCapture(C)) TRY_TO(TraverseDecl(C->getCapturedVar())); return true; } diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h index d1a6063b6b..1dbf5743c1 100644 --- a/include/clang/AST/ExprCXX.h +++ b/include/clang/AST/ExprCXX.h @@ -1452,6 +1452,9 @@ public: return CaptureDefaultLoc; } + /// \brief Determine whether one of this lambda's captures is an init-capture. + bool isInitCapture(const LambdaCapture *Capture) const; + /// \brief An iterator that walks over the captures of the lambda, /// both implicit and explicit. typedef const Capture *capture_iterator; diff --git a/include/clang/AST/LambdaCapture.h b/include/clang/AST/LambdaCapture.h index a7468a0fd5..ddefa88a6b 100644 --- a/include/clang/AST/LambdaCapture.h +++ b/include/clang/AST/LambdaCapture.h @@ -85,11 +85,6 @@ public: (DeclAndBits.getInt() & Capture_ByCopy); } - /// \brief Determine whether this is an init-capture. - bool isInitCapture() const { - return capturesVariable() && getCapturedVar()->isInitCapture(); - } - /// \brief Retrieve the declaration of the local variable being /// captured. /// diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h index 235023d374..129c2b5fe0 100644 --- a/include/clang/AST/RecursiveASTVisitor.h +++ b/include/clang/AST/RecursiveASTVisitor.h @@ -857,7 +857,7 @@ template bool RecursiveASTVisitor::TraverseLambdaCapture(LambdaExpr *LE, const LambdaCapture *C) { - if (C->isInitCapture()) + if (LE->isInitCapture(C)) TRY_TO(TraverseDecl(C->getCapturedVar())); return true; } diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp index f23b3eb79c..d6f2ce63a0 100644 --- a/lib/AST/ExprCXX.cpp +++ b/lib/AST/ExprCXX.cpp @@ -1027,6 +1027,11 @@ LambdaExpr *LambdaExpr::CreateDeserialized(const ASTContext &C, return new (Mem) LambdaExpr(EmptyShell(), NumCaptures, NumArrayIndexVars > 0); } +bool LambdaExpr::isInitCapture(const LambdaCapture *C) const { + return (C->capturesVariable() && C->getCapturedVar()->isInitCapture() && + (getCallOperator() == C->getCapturedVar()->getDeclContext())); +} + LambdaExpr::capture_iterator LambdaExpr::capture_begin() const { return getLambdaClass()->getLambdaData().Captures; } diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp index b68f3a3a26..dc4f9964c7 100644 --- a/lib/AST/StmtPrinter.cpp +++ b/lib/AST/StmtPrinter.cpp @@ -1758,7 +1758,7 @@ void StmtPrinter::VisitLambdaExpr(LambdaExpr *Node) { break; case LCK_ByRef: - if (Node->getCaptureDefault() != LCD_ByRef || C->isInitCapture()) + if (Node->getCaptureDefault() != LCD_ByRef || Node->isInitCapture(C)) OS << '&'; OS << C->getCapturedVar()->getName(); break; @@ -1770,7 +1770,7 @@ void StmtPrinter::VisitLambdaExpr(LambdaExpr *Node) { llvm_unreachable("VLA type in explicit captures."); } - if (C->isInitCapture()) + if (Node->isInitCapture(C)) PrintExpr(C->getCapturedVar()->getInit()); } OS << ']'; diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index 704cef36d4..f5249fdeb0 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -9133,7 +9133,7 @@ TreeTransform::TransformLambdaExpr(LambdaExpr *E) { for (LambdaExpr::capture_iterator C = E->capture_begin(), CEnd = E->capture_end(); C != CEnd; ++C) { - if (!C->isInitCapture()) + if (!E->isInitCapture(C)) continue; EnterExpressionEvaluationContext EEEC(getSema(), Sema::PotentiallyEvaluated); @@ -9245,7 +9245,7 @@ TreeTransform::TransformLambdaExpr(LambdaExpr *E) { continue; // Rebuild init-captures, including the implied field declaration. - if (C->isInitCapture()) { + if (E->isInitCapture(C)) { InitCaptureInfoTy InitExprTypePair = InitCaptureExprsAndTypes[C - E->capture_begin()]; ExprResult Init = InitExprTypePair.first; diff --git a/test/SemaCXX/cxx1y-init-captures.cpp b/test/SemaCXX/cxx1y-init-captures.cpp index 64fe50a70e..203e28d7c3 100644 --- a/test/SemaCXX/cxx1y-init-captures.cpp +++ b/test/SemaCXX/cxx1y-init-captures.cpp @@ -166,4 +166,27 @@ int test(T t = T{}) { int run = test(); //expected-note {{instantiation}} -} \ No newline at end of file +} + +namespace classification_of_captures_of_init_captures { + +template +void f() { + [a = 24] () mutable { + [&a] { a = 3; }(); + }(); +} + +template +void h() { + [a = 24] (auto param) mutable { + [&a] { a = 3; }(); + }(42); +} + +int run() { + f(); + h(); +} + +} -- 2.40.0