aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTareq A. Siraj <tareq.a.sriaj@intel.com>2013-04-16 19:37:38 +0000
committerTareq A. Siraj <tareq.a.sriaj@intel.com>2013-04-16 19:37:38 +0000
commit6afcf8875d4e447645cd7bf3733dd8e2eb8455dc (patch)
tree492ea5c7e442ea915d1f9feeafc8b24624942d96
parent596eea7cc26979c952a0b177d024787a99b299df (diff)
Sema for Captured Statements
Add CapturedDecl to be the DeclContext for CapturedStmt, and perform semantic analysis. Currently captures all variables by reference. TODO: templates Author: Ben Langmuir <ben.langmuir@intel.com> Differential Revision: http://llvm-reviews.chandlerc.com/D433 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@179618 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/AST/Decl.h26
-rw-r--r--include/clang/AST/DeclBase.h1
-rw-r--r--include/clang/AST/RecursiveASTVisitor.h17
-rw-r--r--include/clang/AST/Stmt.h10
-rw-r--r--include/clang/Basic/DeclNodes.td1
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td3
-rw-r--r--include/clang/Sema/ScopeInfo.h50
-rw-r--r--include/clang/Sema/Sema.h15
-rw-r--r--include/clang/Serialization/ASTBitCodes.h2
-rw-r--r--lib/AST/Decl.cpp4
-rw-r--r--lib/AST/DeclBase.cpp2
-rw-r--r--lib/AST/Stmt.cpp16
-rw-r--r--lib/AST/StmtPrinter.cpp2
-rw-r--r--lib/CodeGen/CGDecl.cpp1
-rw-r--r--lib/Frontend/PrintPreprocessedOutput.cpp10
-rw-r--r--lib/Parse/ParsePragma.cpp17
-rw-r--r--lib/Sema/ScopeInfo.cpp1
-rw-r--r--lib/Sema/Sema.cpp17
-rw-r--r--lib/Sema/SemaExpr.cpp63
-rw-r--r--lib/Sema/SemaExprCXX.cpp13
-rw-r--r--lib/Sema/SemaLambda.cpp1
-rw-r--r--lib/Sema/SemaStmt.cpp111
-rw-r--r--lib/Serialization/ASTCommon.cpp2
-rw-r--r--lib/Serialization/ASTReaderDecl.cpp8
-rw-r--r--lib/Serialization/ASTWriterDecl.cpp5
-rw-r--r--test/Sema/captured-statements.c78
-rw-r--r--test/SemaCXX/captured-statements.cpp52
-rw-r--r--tools/libclang/CIndex.cpp1
-rw-r--r--tools/libclang/RecursiveASTVisitor.h17
29 files changed, 515 insertions, 31 deletions
diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h
index 4260ab0bb2..f7286a0388 100644
--- a/include/clang/AST/Decl.h
+++ b/include/clang/AST/Decl.h
@@ -3165,6 +3165,32 @@ public:
}
};
+/// \brief This represents the body of a CapturedStmt, and serves as its
+/// DeclContext.
+class CapturedDecl : public Decl, public DeclContext {
+private:
+ Stmt *Body;
+
+ explicit CapturedDecl(DeclContext *DC)
+ : Decl(Captured, DC, SourceLocation()), DeclContext(Captured) { }
+
+public:
+ static CapturedDecl *Create(ASTContext &C, DeclContext *DC);
+
+ Stmt *getBody() const { return Body; }
+ void setBody(Stmt *B) { Body = B; }
+
+ // Implement isa/cast/dyncast/etc.
+ static bool classof(const Decl *D) { return classofKind(D->getKind()); }
+ static bool classofKind(Kind K) { return K == Captured; }
+ static DeclContext *castToDeclContext(const CapturedDecl *D) {
+ return static_cast<DeclContext *>(const_cast<CapturedDecl *>(D));
+ }
+ static CapturedDecl *castFromDeclContext(const DeclContext *DC) {
+ return static_cast<CapturedDecl *>(const_cast<DeclContext *>(DC));
+ }
+};
+
/// \brief Describes a module import declaration, which makes the contents
/// of the named module visible in the current translation unit.
///
diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h
index a3e69c0af2..bceb703060 100644
--- a/include/clang/AST/DeclBase.h
+++ b/include/clang/AST/DeclBase.h
@@ -1046,6 +1046,7 @@ public:
bool isFunctionOrMethod() const {
switch (DeclKind) {
case Decl::Block:
+ case Decl::Captured:
case Decl::ObjCMethod:
return true;
default:
diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h
index 9b4e481bfd..df41b6fa5a 100644
--- a/include/clang/AST/RecursiveASTVisitor.h
+++ b/include/clang/AST/RecursiveASTVisitor.h
@@ -1228,8 +1228,9 @@ bool RecursiveASTVisitor<Derived>::TraverseDeclContextHelper(DeclContext *DC) {
for (DeclContext::decl_iterator Child = DC->decls_begin(),
ChildEnd = DC->decls_end();
Child != ChildEnd; ++Child) {
- // BlockDecls are traversed through BlockExprs.
- if (!isa<BlockDecl>(*Child))
+ // BlockDecls and CapturedDecls are traversed through BlockExprs and
+ // CapturedStmts respectively.
+ if (!isa<BlockDecl>(*Child) && !isa<CapturedDecl>(*Child))
TRY_TO(TraverseDecl(*Child));
}
@@ -1258,6 +1259,14 @@ DEF_TRAVERSE_DECL(BlockDecl, {
return true;
})
+DEF_TRAVERSE_DECL(CapturedDecl, {
+ TRY_TO(TraverseStmt(D->getBody()));
+ // This return statement makes sure the traversal of nodes in
+ // decls_begin()/decls_end() (done in the DEF_TRAVERSE_DECL macro)
+ // is skipped - don't remove it.
+ return true;
+ })
+
DEF_TRAVERSE_DECL(EmptyDecl, { })
DEF_TRAVERSE_DECL(FileScopeAsmDecl, {
@@ -2218,7 +2227,9 @@ DEF_TRAVERSE_STMT(UnresolvedMemberExpr, {
DEF_TRAVERSE_STMT(SEHTryStmt, {})
DEF_TRAVERSE_STMT(SEHExceptStmt, {})
DEF_TRAVERSE_STMT(SEHFinallyStmt,{})
-DEF_TRAVERSE_STMT(CapturedStmt, {})
+DEF_TRAVERSE_STMT(CapturedStmt, {
+ TRY_TO(TraverseDecl(S->getCapturedDecl()));
+})
DEF_TRAVERSE_STMT(CXXOperatorCallExpr, { })
DEF_TRAVERSE_STMT(OpaqueValueExpr, { })
diff --git a/include/clang/AST/Stmt.h b/include/clang/AST/Stmt.h
index c2cfaa486c..019e678620 100644
--- a/include/clang/AST/Stmt.h
+++ b/include/clang/AST/Stmt.h
@@ -31,9 +31,9 @@ namespace llvm {
namespace clang {
class ASTContext;
class Attr;
+ class CapturedDecl;
class Decl;
class Expr;
- class FunctionDecl;
class IdentifierInfo;
class LabelDecl;
class ParmVarDecl;
@@ -1959,7 +1959,7 @@ private:
unsigned NumCaptures;
/// \brief The implicit outlined function.
- FunctionDecl *TheFuncDecl;
+ CapturedDecl *TheCapturedDecl;
/// \brief The record for captured variables, a RecordDecl or CXXRecordDecl.
RecordDecl *TheRecordDecl;
@@ -1967,7 +1967,7 @@ private:
/// \brief Construct a captured statement.
CapturedStmt(Stmt *S, ArrayRef<Capture> Captures,
ArrayRef<Expr *> CaptureInits,
- FunctionDecl *FD, RecordDecl *RD);
+ CapturedDecl *CD, RecordDecl *RD);
/// \brief Construct an empty captured statement.
CapturedStmt(EmptyShell Empty, unsigned NumCaptures);
@@ -1982,7 +1982,7 @@ public:
static CapturedStmt *Create(ASTContext &Context, Stmt *S,
ArrayRef<Capture> Captures,
ArrayRef<Expr *> CaptureInits,
- FunctionDecl *FD, RecordDecl *RD);
+ CapturedDecl *CD, RecordDecl *RD);
static CapturedStmt *CreateDeserialized(ASTContext &Context,
unsigned NumCaptures);
@@ -1994,7 +1994,7 @@ public:
}
/// \brief Retrieve the outlined function declaration.
- const FunctionDecl *getCapturedFunctionDecl() const { return TheFuncDecl; }
+ CapturedDecl *getCapturedDecl() const { return TheCapturedDecl; }
/// \brief Retrieve the record declaration for captured variables.
const RecordDecl *getCapturedRecordDecl() const { return TheRecordDecl; }
diff --git a/include/clang/Basic/DeclNodes.td b/include/clang/Basic/DeclNodes.td
index ebcd81252f..ad2afa7a57 100644
--- a/include/clang/Basic/DeclNodes.td
+++ b/include/clang/Basic/DeclNodes.td
@@ -73,6 +73,7 @@ def Friend : Decl;
def FriendTemplate : Decl;
def StaticAssert : Decl;
def Block : Decl, DeclContext;
+def Captured : Decl, DeclContext;
def ClassScopeFunctionSpecialization : Decl;
def Import : Decl;
def OMPThreadPrivate : Decl;
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index cfb1798def..fd9ea51df5 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -4804,6 +4804,9 @@ let CategoryName = "Lambda Issue" in {
"here">;
}
+def err_return_in_captured_stmt : Error<
+ "cannot return from %0">;
+
def err_operator_arrow_circular : Error<
"circular pointer delegation detected">;
def err_pseudo_dtor_base_not_scalar : Error<
diff --git a/include/clang/Sema/ScopeInfo.h b/include/clang/Sema/ScopeInfo.h
index 2295bf437c..a48422a308 100644
--- a/include/clang/Sema/ScopeInfo.h
+++ b/include/clang/Sema/ScopeInfo.h
@@ -24,6 +24,7 @@ namespace clang {
class Decl;
class BlockDecl;
+class CapturedDecl;
class CXXMethodDecl;
class ObjCPropertyDecl;
class IdentifierInfo;
@@ -73,7 +74,8 @@ protected:
enum ScopeKind {
SK_Function,
SK_Block,
- SK_Lambda
+ SK_Lambda,
+ SK_CapturedRegion
};
public:
@@ -319,7 +321,8 @@ public:
class CapturingScopeInfo : public FunctionScopeInfo {
public:
enum ImplicitCaptureStyle {
- ImpCap_None, ImpCap_LambdaByval, ImpCap_LambdaByref, ImpCap_Block
+ ImpCap_None, ImpCap_LambdaByval, ImpCap_LambdaByref, ImpCap_Block,
+ ImpCap_CapturedRegion
};
ImplicitCaptureStyle ImpCaptureStyle;
@@ -461,7 +464,8 @@ public:
}
static bool classof(const FunctionScopeInfo *FSI) {
- return FSI->Kind == SK_Block || FSI->Kind == SK_Lambda;
+ return FSI->Kind == SK_Block || FSI->Kind == SK_Lambda
+ || FSI->Kind == SK_CapturedRegion;
}
};
@@ -492,6 +496,46 @@ public:
}
};
+/// \brief Retains information about a captured region.
+class CapturedRegionScopeInfo: public CapturingScopeInfo {
+public:
+
+ enum CapturedRegionKind {
+ CR_Default
+ };
+
+ /// \brief The CapturedDecl for this statement.
+ CapturedDecl *TheCapturedDecl;
+ /// \brief The captured record type.
+ RecordDecl *TheRecordDecl;
+ /// \brief This is the enclosing scope of the captured region.
+ Scope *TheScope;
+ /// \brief The kind of captured region.
+ CapturedRegionKind CapRegionKind;
+
+ CapturedRegionScopeInfo(DiagnosticsEngine &Diag, Scope *S, CapturedDecl *CD,
+ RecordDecl *RD, CapturedRegionKind K)
+ : CapturingScopeInfo(Diag, ImpCap_CapturedRegion),
+ TheCapturedDecl(CD), TheRecordDecl(RD), TheScope(S), CapRegionKind(K)
+ {
+ Kind = SK_CapturedRegion;
+ }
+
+ virtual ~CapturedRegionScopeInfo();
+
+ /// \brief A descriptive name for the kind of captured region this is.
+ StringRef getRegionName() const {
+ switch (CapRegionKind) {
+ case CR_Default:
+ return "default captured statement";
+ }
+ }
+
+ static bool classof(const FunctionScopeInfo *FSI) {
+ return FSI->Kind == SK_CapturedRegion;
+ }
+};
+
class LambdaScopeInfo : public CapturingScopeInfo {
public:
/// \brief The class that describes the lambda.
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index 01e646ef4d..f95d6a4321 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -37,6 +37,7 @@
#include "clang/Sema/LocInfoType.h"
#include "clang/Sema/ObjCMethodList.h"
#include "clang/Sema/Ownership.h"
+#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/TypoCorrection.h"
#include "clang/Sema/Weak.h"
#include "llvm/ADT/ArrayRef.h"
@@ -65,6 +66,7 @@ namespace clang {
class ArrayType;
class AttributeList;
class BlockDecl;
+ class CapturedDecl;
class CXXBasePath;
class CXXBasePaths;
class CXXBindTemporaryExpr;
@@ -174,6 +176,7 @@ namespace clang {
namespace sema {
class AccessedEntity;
class BlockScopeInfo;
+ class CapturedRegionScopeInfo;
class CapturingScopeInfo;
class CompoundScopeInfo;
class DelayedDiagnostic;
@@ -916,6 +919,9 @@ public:
void PushFunctionScope();
void PushBlockScope(Scope *BlockScope, BlockDecl *Block);
void PushLambdaScope(CXXRecordDecl *Lambda, CXXMethodDecl *CallOperator);
+ void PushCapturedRegionScope(Scope *RegionScope, CapturedDecl *CD,
+ RecordDecl *RD,
+ sema::CapturedRegionScopeInfo::CapturedRegionKind K);
void PopFunctionScopeInfo(const sema::AnalysisBasedWarnings::Policy *WP =0,
const Decl *D = 0, const BlockExpr *blkExpr = 0);
@@ -936,6 +942,9 @@ public:
/// \brief Retrieve the current lambda expression, if any.
sema::LambdaScopeInfo *getCurLambda();
+ /// \brief Retrieve the current captured region, if any.
+ sema::CapturedRegionScopeInfo *getCurCapturedRegion();
+
/// WeakTopLevelDeclDecls - access to \#pragma weak-generated Decls
SmallVector<Decl*,2> &WeakTopLevelDecls() { return WeakTopLevelDecl; }
@@ -2767,6 +2776,12 @@ public:
StmtResult ActOnContinueStmt(SourceLocation ContinueLoc, Scope *CurScope);
StmtResult ActOnBreakStmt(SourceLocation BreakLoc, Scope *CurScope);
+ void ActOnCapturedRegionStart(SourceLocation Loc, Scope *CurScope,
+ sema::CapturedRegionScopeInfo::CapturedRegionKind Kind);
+ StmtResult ActOnCapturedRegionEnd(Stmt *S);
+ void ActOnCapturedRegionError(bool IsInstantiation = false);
+ RecordDecl *CreateCapturedStmtRecordDecl(CapturedDecl *&CD,
+ SourceLocation Loc);
const VarDecl *getCopyElisionCandidate(QualType ReturnType, Expr *E,
bool AllowFunctionParameters);
diff --git a/include/clang/Serialization/ASTBitCodes.h b/include/clang/Serialization/ASTBitCodes.h
index 04d6a85860..9f5e8b1224 100644
--- a/include/clang/Serialization/ASTBitCodes.h
+++ b/include/clang/Serialization/ASTBitCodes.h
@@ -963,6 +963,8 @@ namespace clang {
DECL_FILE_SCOPE_ASM,
/// \brief A BlockDecl record.
DECL_BLOCK,
+ /// \brief A CapturedDecl record.
+ DECL_CAPTURED,
/// \brief A record that stores the set of declarations that are
/// lexically stored within a given DeclContext.
///
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index 36044826e8..d572335fb3 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -3234,6 +3234,10 @@ MSPropertyDecl *MSPropertyDecl::CreateDeserialized(ASTContext &C,
0, 0);
}
+CapturedDecl *CapturedDecl::Create(ASTContext &C, DeclContext *DC) {
+ return new (C) CapturedDecl(DC);
+}
+
EnumConstantDecl *EnumConstantDecl::Create(ASTContext &C, EnumDecl *CD,
SourceLocation L,
IdentifierInfo *Id, QualType T,
diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp
index 3f23f3d855..402d83683a 100644
--- a/lib/AST/DeclBase.cpp
+++ b/lib/AST/DeclBase.cpp
@@ -553,6 +553,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
case StaticAssert:
case ObjCPropertyImpl:
case Block:
+ case Captured:
case TranslationUnit:
case UsingDirective:
@@ -839,6 +840,7 @@ DeclContext *DeclContext::getPrimaryContext() {
case Decl::TranslationUnit:
case Decl::LinkageSpec:
case Decl::Block:
+ case Decl::Captured:
// There is only one DeclContext for these entities.
return this;
diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp
index e120c6a1f8..2a7b170222 100644
--- a/lib/AST/Stmt.cpp
+++ b/lib/AST/Stmt.cpp
@@ -1038,12 +1038,12 @@ CapturedStmt::Capture *CapturedStmt::getStoredCaptures() const {
CapturedStmt::CapturedStmt(Stmt *S, ArrayRef<Capture> Captures,
ArrayRef<Expr *> CaptureInits,
- FunctionDecl *FD,
+ CapturedDecl *CD,
RecordDecl *RD)
: Stmt(CapturedStmtClass), NumCaptures(Captures.size()),
- TheFuncDecl(FD), TheRecordDecl(RD) {
+ TheCapturedDecl(CD), TheRecordDecl(RD) {
assert( S && "null captured statement");
- assert(FD && "null function declaration for captured statement");
+ assert(CD && "null captured declaration for captured statement");
assert(RD && "null record declaration for captured statement");
// Copy initialization expressions.
@@ -1061,14 +1061,14 @@ CapturedStmt::CapturedStmt(Stmt *S, ArrayRef<Capture> Captures,
CapturedStmt::CapturedStmt(EmptyShell Empty, unsigned NumCaptures)
: Stmt(CapturedStmtClass, Empty), NumCaptures(NumCaptures),
- TheFuncDecl(0), TheRecordDecl(0) {
+ TheCapturedDecl(0), TheRecordDecl(0) {
getStoredStmts()[NumCaptures] = 0;
}
CapturedStmt *CapturedStmt::Create(ASTContext &Context, Stmt *S,
ArrayRef<Capture> Captures,
ArrayRef<Expr *> CaptureInits,
- FunctionDecl *FD,
+ CapturedDecl *CD,
RecordDecl *RD) {
// The layout is
//
@@ -1089,7 +1089,7 @@ CapturedStmt *CapturedStmt::Create(ASTContext &Context, Stmt *S,
}
void *Mem = Context.Allocate(Size);
- return new (Mem) CapturedStmt(S, Captures, CaptureInits, FD, RD);
+ return new (Mem) CapturedStmt(S, Captures, CaptureInits, CD, RD);
}
CapturedStmt *CapturedStmt::CreateDeserialized(ASTContext &Context,
@@ -1106,8 +1106,8 @@ CapturedStmt *CapturedStmt::CreateDeserialized(ASTContext &Context,
}
Stmt::child_range CapturedStmt::children() {
- // Children are captured field initilizers and the statement being captured.
- return child_range(getStoredStmts(), getStoredStmts() + NumCaptures + 1);
+ // Children are captured field initilizers.
+ return child_range(getStoredStmts(), getStoredStmts() + NumCaptures);
}
bool CapturedStmt::capturesVariable(const VarDecl *Var) const {
diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp
index 469c2846a6..1b2285c794 100644
--- a/lib/AST/StmtPrinter.cpp
+++ b/lib/AST/StmtPrinter.cpp
@@ -451,7 +451,7 @@ void StmtPrinter::VisitMSAsmStmt(MSAsmStmt *Node) {
}
void StmtPrinter::VisitCapturedStmt(CapturedStmt *Node) {
- PrintStmt(Node->getCapturedStmt());
+ PrintStmt(Node->getCapturedDecl()->getBody());
}
void StmtPrinter::VisitObjCAtTryStmt(ObjCAtTryStmt *Node) {
diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp
index 15bb6a6e45..173ca6cb09 100644
--- a/lib/CodeGen/CGDecl.cpp
+++ b/lib/CodeGen/CGDecl.cpp
@@ -70,6 +70,7 @@ void CodeGenFunction::EmitDecl(const Decl &D) {
case Decl::Friend:
case Decl::FriendTemplate:
case Decl::Block:
+ case Decl::Captured:
case Decl::ClassScopeFunctionSpecialization:
llvm_unreachable("Declaration should not be in declstmts!");
case Decl::Function: // void X();
diff --git a/lib/Frontend/PrintPreprocessedOutput.cpp b/lib/Frontend/PrintPreprocessedOutput.cpp
index 6734d7759b..7e1cae95d7 100644
--- a/lib/Frontend/PrintPreprocessedOutput.cpp
+++ b/lib/Frontend/PrintPreprocessedOutput.cpp
@@ -137,6 +137,7 @@ public:
StringRef RelativePath,
const Module *Imported);
virtual void Ident(SourceLocation Loc, const std::string &str);
+ virtual void PragmaCaptured(SourceLocation Loc, StringRef Str);
virtual void PragmaComment(SourceLocation Loc, const IdentifierInfo *Kind,
const std::string &Str);
virtual void PragmaMessage(SourceLocation Loc, StringRef Str);
@@ -345,6 +346,15 @@ void PrintPPOutputPPCallbacks::Ident(SourceLocation Loc, const std::string &S) {
EmittedTokensOnThisLine = true;
}
+void PrintPPOutputPPCallbacks::PragmaCaptured(SourceLocation Loc,
+ StringRef Str) {
+ startNewLineIfNeeded();
+ MoveToLine(Loc);
+ OS << "#pragma captured";
+
+ setEmittedDirectiveOnThisLine();
+}
+
/// MacroDefined - This hook is called whenever a macro definition is seen.
void PrintPPOutputPPCallbacks::MacroDefined(const Token &MacroNameTok,
const MacroDirective *MD) {
diff --git a/lib/Parse/ParsePragma.cpp b/lib/Parse/ParsePragma.cpp
index 038636d108..96328e2fb6 100644
--- a/lib/Parse/ParsePragma.cpp
+++ b/lib/Parse/ParsePragma.cpp
@@ -15,6 +15,7 @@
#include "clang/Lex/Preprocessor.h"
#include "clang/Parse/ParseDiagnostic.h"
#include "clang/Parse/Parser.h"
+#include "clang/Sema/Scope.h"
using namespace clang;
/// \brief Handle the annotation token produced for #pragma unused(...)
@@ -132,7 +133,21 @@ StmtResult Parser::HandlePragmaCaptured()
return StmtError();
}
- return StmtEmpty();
+ SourceLocation Loc = Tok.getLocation();
+
+ ParseScope CapturedRegionScope(this, Scope::FnScope | Scope::DeclScope);
+ Actions.ActOnCapturedRegionStart(Loc, getCurScope(),
+ sema::CapturedRegionScopeInfo::CR_Default);
+
+ StmtResult R = ParseCompoundStatement();
+ CapturedRegionScope.Exit();
+
+ if (R.isInvalid()) {
+ Actions.ActOnCapturedRegionError();
+ return StmtError();
+ }
+
+ return Actions.ActOnCapturedRegionEnd(R.get());
}
namespace {
diff --git a/lib/Sema/ScopeInfo.cpp b/lib/Sema/ScopeInfo.cpp
index 4d29a34a73..2f48bec123 100644
--- a/lib/Sema/ScopeInfo.cpp
+++ b/lib/Sema/ScopeInfo.cpp
@@ -187,3 +187,4 @@ void FunctionScopeInfo::markSafeWeakUse(const Expr *E) {
FunctionScopeInfo::~FunctionScopeInfo() { }
BlockScopeInfo::~BlockScopeInfo() { }
LambdaScopeInfo::~LambdaScopeInfo() { }
+CapturedRegionScopeInfo::~CapturedRegionScopeInfo() { }
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp
index 6425f34ff5..203b689aa1 100644
--- a/lib/Sema/Sema.cpp
+++ b/lib/Sema/Sema.cpp
@@ -802,7 +802,7 @@ DeclContext *Sema::getFunctionLevelDeclContext() {
DeclContext *DC = CurContext;
while (true) {
- if (isa<BlockDecl>(DC) || isa<EnumDecl>(DC)) {
+ if (isa<BlockDecl>(DC) || isa<EnumDecl>(DC) || isa<CapturedDecl>(DC)) {
DC = DC->getParent();
} else if (isa<CXXMethodDecl>(DC) &&
cast<CXXMethodDecl>(DC)->getOverloadedOperator() == OO_Call &&
@@ -1314,3 +1314,18 @@ IdentifierInfo *Sema::getSuperIdentifier() const {
Ident_super = &Context.Idents.get("super");
return Ident_super;
}
+
+void Sema::PushCapturedRegionScope(Scope *S, CapturedDecl *CD, RecordDecl *RD,
+ CapturedRegionScopeInfo::CapturedRegionKind K) {
+ CapturingScopeInfo *CSI = new CapturedRegionScopeInfo(getDiagnostics(),
+ S, CD, RD, K);
+ CSI->ReturnType = Context.VoidTy;
+ FunctionScopes.push_back(CSI);
+}
+
+CapturedRegionScopeInfo *Sema::getCurCapturedRegion() {
+ if (FunctionScopes.empty())
+ return 0;
+
+ return dyn_cast<CapturedRegionScopeInfo>(FunctionScopes.back());
+}
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index e96c5d40a3..cdfdc09e06 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -10851,6 +10851,34 @@ diagnoseUncapturableValueReference(Sema &S, SourceLocation loc,
// capture.
}
+/// \brief Capture the given variable in the captured region.
+static ExprResult captureInCapturedRegion(Sema &S, CapturedRegionScopeInfo *RSI,
+ VarDecl *Var, QualType FieldType,
+ QualType DeclRefType,
+ SourceLocation Loc,
+ bool RefersToEnclosingLocal) {
+ // The current implemention assumes that all variables are captured
+ // by references. Since there is no capture by copy, no expression evaluation
+ // will be needed.
+ //
+ RecordDecl *RD = RSI->TheRecordDecl;
+
+ FieldDecl *Field
+ = FieldDecl::Create(S.Context, RD, Loc, Loc, 0, FieldType,
+ S.Context.getTrivialTypeSourceInfo(FieldType, Loc),
+ 0, false, ICIS_NoInit);
+ Field->setImplicit(true);
+ Field->setAccess(AS_private);
+ RD->addDecl(Field);
+
+ Expr *Ref = new (S.Context) DeclRefExpr(Var, RefersToEnclosingLocal,
+ DeclRefType, VK_LValue, Loc);
+ Var->setReferenced(true);
+ Var->setUsed(true);
+
+ return Ref;
+}
+
/// \brief Capture the given variable in the given lambda expression.
static ExprResult captureInLambda(Sema &S, LambdaScopeInfo *LSI,
VarDecl *Var, QualType FieldType,
@@ -10991,10 +11019,10 @@ bool Sema::tryCaptureVariable(VarDecl *Var, SourceLocation Loc,
bool Explicit = (Kind != TryCapture_Implicit);
unsigned FunctionScopesIndex = FunctionScopes.size() - 1;
do {
- // Only block literals and lambda expressions can capture; other
- // scopes don't work.
+ // Only block literals, captured statements, and lambda expressions can
+ // capture; other scopes don't work.
DeclContext *ParentDC;
- if (isa<BlockDecl>(DC))
+ if (isa<BlockDecl>(DC) || isa<CapturedDecl>(DC))
ParentDC = DC->getParent();
else if (isa<CXXMethodDecl>(DC) &&
cast<CXXMethodDecl>(DC)->getOverloadedOperator() == OO_Call &&
@@ -11028,7 +11056,7 @@ bool Sema::tryCaptureVariable(VarDecl *Var, SourceLocation Loc,
}
bool IsBlock = isa<BlockScopeInfo>(CSI);
- bool IsLambda = !IsBlock;
+ bool IsLambda = isa<LambdaScopeInfo>(CSI);
// Lambdas are not allowed to capture unnamed variables
// (e.g. anonymous unions).
@@ -11188,8 +11216,31 @@ bool Sema::tryCaptureVariable(VarDecl *Var, SourceLocation Loc,
SourceLocation(), CaptureType, CopyExpr);
Nested = true;
continue;
- }
-
+ }
+
+ if (CapturedRegionScopeInfo *RSI = dyn_cast<CapturedRegionScopeInfo>(CSI)) {
+ // By default, capture variables by reference.
+ bool ByRef = true;
+ // Using an LValue reference type is consistent with Lambdas (see below).
+ CaptureType = Context.getLValueReferenceType(DeclRefType);
+
+ Expr *CopyExpr = 0;
+ if (BuildAndDiagnose) {
+ ExprResult Result = captureInCapturedRegion(*this, RSI, Var,
+ CaptureType, DeclRefType,
+ Loc, Nested);
+ if (!Result.isInvalid())
+ CopyExpr = Result.take();
+ }
+
+ // Actually capture the variable.
+ if (BuildAndDiagnose)
+ CSI->addCapture(Var, /*isBlock*/false, ByRef, Nested, Loc,
+ SourceLocation(), CaptureType, CopyExpr);
+ Nested = true;
+ continue;
+ }
+
LambdaScopeInfo *LSI = cast<LambdaScopeInfo>(CSI);
// Determine whether we are capturing by reference or by value.
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index cfc00502c4..89c1bc51c3 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -746,6 +746,7 @@ void Sema::CheckCXXThisCapture(SourceLocation Loc, bool Explicit) {
if (CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_LambdaByref ||
CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_LambdaByval ||
CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_Block ||
+ CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_CapturedRegion ||
Explicit) {
// This closure can capture 'this'; continue looking upwards.
NumClosures++;
@@ -778,7 +779,19 @@ void Sema::CheckCXXThisCapture(SourceLocation Loc, bool Explicit) {
Field->setAccess(AS_private);
Lambda->addDecl(Field);
ThisExpr = new (Context) CXXThisExpr(Loc, ThisTy, /*isImplicit=*/true);
+ } else if (CapturedRegionScopeInfo *RSI =
+ dyn_cast<CapturedRegionScopeInfo>(FunctionScopes[idx])) {
+ RecordDecl *RD = RSI->TheRecordDecl;
+ FieldDecl *Field
+ = FieldDecl::Create(Context, RD, Loc, Loc, 0, ThisTy,
+ Context.getTrivialTypeSourceInfo(ThisTy, Loc),
+ 0, false, ICIS_NoInit);
+ Field->setImplicit(true);
+ Field->setAccess(AS_private);
+ RD->addDecl(Field);
+ ThisExpr = new (Context) CXXThisExpr(Loc, ThisTy, /*isImplicit*/true);
}
+
bool isNested = NumClosures > 1;
CSI->addThisCapture(isNested, Loc, ThisTy, ThisExpr);
}
diff --git a/lib/Sema/SemaLambda.cpp b/lib/Sema/SemaLambda.cpp
index 53fa6dafdd..77e6bfd086 100644
--- a/lib/Sema/SemaLambda.cpp
+++ b/lib/Sema/SemaLambda.cpp
@@ -862,6 +862,7 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body,
CaptureDefault = LCD_ByCopy;
break;
+ case CapturingScopeInfo::ImpCap_CapturedRegion:
case CapturingScopeInfo::ImpCap_LambdaByref:
CaptureDefault = LCD_ByRef;
break;
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp
index b3558a548b..88237b08b2 100644
--- a/lib/Sema/SemaStmt.cpp
+++ b/lib/Sema/SemaStmt.cpp
@@ -2403,6 +2403,10 @@ Sema::ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
Diag(ReturnLoc, diag::err_noreturn_block_has_return_expr);
return StmtError();
}
+ } else if (CapturedRegionScopeInfo *CurRegion =
+ dyn_cast<CapturedRegionScopeInfo>(CurCap)) {
+ Diag(ReturnLoc, diag::err_return_in_captured_stmt) << CurRegion->getRegionName();
+ return StmtError();
} else {
LambdaScopeInfo *LSI = cast<LambdaScopeInfo>(CurCap);
if (LSI->CallOperator->getType()->getAs<FunctionType>()->getNoReturnAttr()){
@@ -2914,3 +2918,110 @@ StmtResult Sema::ActOnMSDependentExistsStmt(SourceLocation KeywordLoc,
GetNameFromUnqualifiedId(Name),
Nested);
}
+
+RecordDecl*
+Sema::CreateCapturedStmtRecordDecl(CapturedDecl *&CD, SourceLocation Loc)
+{
+ DeclContext *DC = CurContext;
+ while (!(DC->isFunctionOrMethod() || DC->isRecord() || DC->isFileContext()))
+ DC = DC->getParent();
+
+ RecordDecl *RD = 0;
+ if (getLangOpts().CPlusPlus)
+ RD = CXXRecordDecl::Create(Context, TTK_Struct, DC, Loc, Loc, /*Id=*/0);
+ else
+ RD = RecordDecl::Create(Context, TTK_Struct, DC, Loc, Loc, /*Id=*/0);
+
+ DC->addDecl(RD);
+ RD->setImplicit();
+ RD->startDefinition();
+
+ CD = CapturedDecl::Create(Context, CurContext);
+ DC->addDecl(CD);
+
+ return RD;
+}
+
+static void buildCapturedStmtCaptureList(
+ SmallVectorImpl<CapturedStmt::Capture> &Captures,
+ SmallVectorImpl<Expr *> &CaptureInits,
+ ArrayRef<CapturingScopeInfo::Capture> Candidates) {
+
+ typedef ArrayRef<CapturingScopeInfo::Capture>::const_iterator CaptureIter;
+ for (CaptureIter Cap = Candidates.begin(); Cap != Candidates.end(); ++Cap) {
+
+ if (Cap->isThisCapture()) {
+ Captures.push_back(CapturedStmt::Capture(Cap->getLocation(),
+ CapturedStmt::VCK_This));
+ CaptureInits.push_back(Cap->getCopyExpr());
+ continue;
+ }
+
+ assert(Cap->isReferenceCapture() &&
+ "non-reference capture not yet implemented");
+
+ Captures.push_back(CapturedStmt::Capture(Cap->getLocation(),
+ CapturedStmt::VCK_ByRef,
+ Cap->getVariable()));
+ CaptureInits.push_back(Cap->getCopyExpr());
+ }
+}
+
+void Sema::ActOnCapturedRegionStart(SourceLocation Loc, Scope *CurScope,
+ CapturedRegionScopeInfo::CapturedRegionKind Kind) {
+ CapturedDecl *CD = 0;
+ RecordDecl *RD = CreateCapturedStmtRecordDecl(CD, Loc);
+
+ // Enter the capturing scope for this captured region.
+ PushCapturedRegionScope(CurScope, CD, RD, Kind);
+
+ if (CurScope)
+ PushDeclContext(CurScope, CD);
+ else
+ CurContext = CD;
+
+ PushExpressionEvaluationContext(PotentiallyEvaluated);
+}
+
+void Sema::ActOnCapturedRegionError(bool IsInstantiation) {
+ DiscardCleanupsInEvaluationContext();
+ PopExpressionEvaluationContext();
+
+ if (!IsInstantiation)
+ PopDeclContext();
+
+ CapturedRegionScopeInfo *RSI = getCurCapturedRegion();
+ RecordDecl *Record = RSI->TheRecordDecl;
+ Record->setInvalidDecl();
+
+ SmallVector<Decl*, 4> Fields;
+ for (RecordDecl::field_iterator I = Record->field_begin(),
+ E = Record->field_end(); I != E; ++I)
+ Fields.push_back(*I);
+ ActOnFields(/*Scope=*/0, Record->getLocation(), Record, Fields,
+ SourceLocation(), SourceLocation(), /*AttributeList=*/0);
+
+ PopFunctionScopeInfo();
+}
+
+StmtResult Sema::ActOnCapturedRegionEnd(Stmt *S) {
+ CapturedRegionScopeInfo *RSI = getCurCapturedRegion();
+
+ SmallVector<CapturedStmt::Capture, 4> Captures;
+ SmallVector<Expr *, 4> CaptureInits;
+ buildCapturedStmtCaptureList(Captures, CaptureInits, RSI->Captures);
+
+ CapturedDecl *CD = RSI->TheCapturedDecl;
+ RecordDecl *RD = RSI->TheRecordDecl;
+
+ CapturedStmt *Res = CapturedStmt::Create(getASTContext(), S, Captures,
+ CaptureInits, CD, RD);
+
+ CD->setBody(Res->getCapturedStmt());
+ RD->completeDefinition();
+
+ PopDeclContext();
+ PopFunctionScopeInfo();
+
+ return Owned(Res);
+}
diff --git a/lib/Serialization/ASTCommon.cpp b/lib/Serialization/ASTCommon.cpp
index e8cc1553aa..24b268f36d 100644
--- a/lib/Serialization/ASTCommon.cpp
+++ b/lib/Serialization/ASTCommon.cpp
@@ -119,6 +119,7 @@ serialization::getDefinitiveDeclContext(const DeclContext *DC) {
case Decl::CXXConversion:
case Decl::ObjCMethod:
case Decl::Block:
+ case Decl::Captured:
// Objective C categories, category implementations, and class
// implementations can only be defined in one place.
case Decl::ObjCCategory:
@@ -203,6 +204,7 @@ bool serialization::isRedeclarableDeclKind(unsigned Kind) {
case Decl::FriendTemplate:
case Decl::StaticAssert:
case Decl::Block:
+ case Decl::Captured:
case Decl::ClassScopeFunctionSpecialization:
case Decl::Import:
case Decl::OMPThreadPrivate:
diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp
index 02295d09be..949f593434 100644
--- a/lib/Serialization/ASTReaderDecl.cpp
+++ b/lib/Serialization/ASTReaderDecl.cpp
@@ -266,6 +266,7 @@ namespace clang {
void VisitFriendTemplateDecl(FriendTemplateDecl *D);
void VisitStaticAssertDecl(StaticAssertDecl *D);
void VisitBlockDecl(BlockDecl *BD);
+ void VisitCapturedDecl(CapturedDecl *CD);
void VisitEmptyDecl(EmptyDecl *D);
std::pair<uint64_t, uint64_t> VisitDeclContext(DeclContext *DC);
@@ -994,6 +995,10 @@ void ASTDeclReader::VisitBlockDecl(BlockDecl *BD) {
captures.end(), capturesCXXThis);
}
+void ASTDeclReader::VisitCapturedDecl(CapturedDecl *) {
+ llvm_unreachable("not implemented yet");
+}
+
void ASTDeclReader::VisitLinkageSpecDecl(LinkageSpecDecl *D) {
VisitDecl(D);
D->setLanguage((LinkageSpecDecl::LanguageIDs)Record[Idx++]);
@@ -2146,6 +2151,9 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) {
case DECL_MS_PROPERTY:
D = MSPropertyDecl::CreateDeserialized(Context, ID);
break;
+ case DECL_CAPTURED:
+ llvm_unreachable("not implemented yet");
+ break;
case DECL_CXX_BASE_SPECIFIERS:
Error("attempt to read a C++ base-specifier record as a declaration");
return 0;
diff --git a/lib/Serialization/ASTWriterDecl.cpp b/lib/Serialization/ASTWriterDecl.cpp
index 7d21c584aa..b7ca623d7d 100644
--- a/lib/Serialization/ASTWriterDecl.cpp
+++ b/lib/Serialization/ASTWriterDecl.cpp
@@ -103,6 +103,7 @@ namespace clang {
void VisitFriendTemplateDecl(FriendTemplateDecl *D);
void VisitStaticAssertDecl(StaticAssertDecl *D);
void VisitBlockDecl(BlockDecl *D);
+ void VisitCapturedDecl(CapturedDecl *D);
void VisitEmptyDecl(EmptyDecl *D);
void VisitDeclContext(DeclContext *DC, uint64_t LexicalOffset,
@@ -824,6 +825,10 @@ void ASTDeclWriter::VisitBlockDecl(BlockDecl *D) {
Code = serialization::DECL_BLOCK;
}
+void ASTDeclWriter::VisitCapturedDecl(CapturedDecl *) {
+ llvm_unreachable("not implemented yet");
+}
+
void ASTDeclWriter::VisitLinkageSpecDecl(LinkageSpecDecl *D) {
VisitDecl(D);
Record.push_back(D->getLanguage());
diff --git a/test/Sema/captured-statements.c b/test/Sema/captured-statements.c
new file mode 100644
index 0000000000..9285a7802d
--- /dev/null
+++ b/test/Sema/captured-statements.c
@@ -0,0 +1,78 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s -fblocks
+
+void test_gotos() {
+ goto L1; // expected-error {{use of undeclared label 'L1'}}
+ goto L3; // OK
+ #pragma clang __debug captured
+ {
+L1:
+ goto L2; // OK
+L2:
+ goto L3; // expected-error {{use of undeclared label 'L3'}}
+ }
+L3: ;
+}
+
+void test_break_continue() {
+ while (1) {
+ #pragma clang __debug captured
+ {
+ break; // expected-error {{'break' statement not in loop or switch statement}}
+ continue; // expected-error {{'continue' statement not in loop statement}}
+ }
+ }
+}
+
+void test_return() {
+ while (1) {
+ #pragma clang __debug captured
+ {
+ return; // expected-error {{cannot return from default captured statement}}
+ }
+ }
+}
+
+void test_nest() {
+ int x;
+ #pragma clang __debug captured
+ {
+ int y;
+ #pragma clang __debug captured
+ {
+ int z;
+ #pragma clang __debug captured
+ {
+ x = z = y; // OK
+ }
+ }
+ }
+}
+
+void test_nest_block() {
+ __block int x;
+ int y;
+ ^{
+ int z;
+ #pragma clang __debug captured
+ {
+ x = y; // OK
+ y = z; // expected-error{{variable is not assignable (missing __block type specifier)}}
+ z = y; // OK
+ }
+ }();
+
+ __block int a;
+ int b;
+ #pragma clang __debug captured
+ {
+ __block int c;
+ int d;
+ ^{
+ a = b; // OK
+ a = c; // OK
+ b = d; // OK - Consistent with block inside a lambda
+ c = a; // OK
+ d = b; // expected-error{{variable is not assignable (missing __block type specifier)}}
+ }();
+ }
+}
diff --git a/test/SemaCXX/captured-statements.cpp b/test/SemaCXX/captured-statements.cpp
new file mode 100644
index 0000000000..15879a1ebc
--- /dev/null
+++ b/test/SemaCXX/captured-statements.cpp
@@ -0,0 +1,52 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s -fblocks
+
+void test_nest_lambda() {
+ int x;
+ int y;
+ [&,y]() {
+ int z;
+ #pragma clang __debug captured
+ {
+ x = y; // OK
+ y = z; // expected-error{{cannot assign to a variable captured by copy in a non-mutable lambda}}
+ z = y; // OK
+ }
+ }();
+
+ int a;
+ #pragma clang __debug captured
+ {
+ int b;
+ int c;
+ [&,c]() {
+ a = b; // OK
+ b = c; // OK
+ c = a; // expected-error{{cannot assign to a variable captured by copy in a non-mutable lambda}}
+ }();
+ }
+}
+
+class test_obj_capture {
+ int a;
+ void b();
+ static void test() {
+ test_obj_capture c;
+ #pragma clang __debug captured
+ { (void)c.a; } // OK
+ #pragma clang __debug captured
+ { c.b(); } // OK
+ }
+};
+
+class test_this_capture {
+ int a;
+ void b();
+ void test() {
+ #pragma clang __debug captured
+ { (void)this; } // OK
+ #pragma clang __debug captured
+ { (void)a; } // OK
+ #pragma clang __debug captured
+ { b(); } // OK
+ }
+};
diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp
index d1aeee04ea..95b49fcd25 100644
--- a/tools/libclang/CIndex.cpp
+++ b/tools/libclang/CIndex.cpp
@@ -4474,6 +4474,7 @@ CXCursor clang_getCursorDefinition(CXCursor C) {
case Decl::FileScopeAsm:
case Decl::StaticAssert:
case Decl::Block:
+ case Decl::Captured:
case Decl::Label: // FIXME: Is this right??
case Decl::ClassScopeFunctionSpecialization:
case Decl::Import:
diff --git a/tools/libclang/RecursiveASTVisitor.h b/tools/libclang/RecursiveASTVisitor.h
index 592f168725..6c9da93b73 100644
--- a/tools/libclang/RecursiveASTVisitor.h
+++ b/tools/libclang/RecursiveASTVisitor.h
@@ -1170,8 +1170,9 @@ bool RecursiveASTVisitor<Derived>::TraverseDeclContextHelper(DeclContext *DC) {
for (DeclContext::decl_iterator Child = DC->decls_begin(),
ChildEnd = DC->decls_end();
Child != ChildEnd; ++Child) {
- // BlockDecls are traversed through BlockExprs.
- if (!isa<BlockDecl>(*Child))
+ // BlockDecls and CapturedDecls are traversed through BlockExprs and
+ // CapturedStmts respectively.
+ if (!isa<BlockDecl>(*Child) && !isa<CapturedDecl>(*Child))
TRY_TO(TraverseDecl(*Child));
}
@@ -1200,6 +1201,14 @@ DEF_TRAVERSE_DECL(BlockDecl, {
return true;
})
+DEF_TRAVERSE_DECL(CapturedDecl, {
+ TRY_TO(TraverseStmt(D->getBody()));
+ // This return statement makes sure the traversal of nodes in
+ // decls_begin()/decls_end() (done in the DEF_TRAVERSE_DECL macro)
+ // is skipped - don't remove it.
+ return true;
+ })
+
DEF_TRAVERSE_DECL(EmptyDecl, { })
DEF_TRAVERSE_DECL(FileScopeAsmDecl, {
@@ -1839,7 +1848,6 @@ DEF_TRAVERSE_STMT(MSDependentExistsStmt, {
DEF_TRAVERSE_STMT(ReturnStmt, { })
DEF_TRAVERSE_STMT(SwitchStmt, { })
DEF_TRAVERSE_STMT(WhileStmt, { })
-DEF_TRAVERSE_STMT(CapturedStmt, { })
DEF_TRAVERSE_STMT(CXXDependentScopeMemberExpr, {
TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc()));
@@ -2141,6 +2149,9 @@ DEF_TRAVERSE_STMT(MSPropertyRefExpr, {})
DEF_TRAVERSE_STMT(SEHTryStmt, {})
DEF_TRAVERSE_STMT(SEHExceptStmt, {})
DEF_TRAVERSE_STMT(SEHFinallyStmt,{})
+DEF_TRAVERSE_STMT(CapturedStmt, {
+ TRY_TO(TraverseDecl(S->getCapturedDecl()));
+})
DEF_TRAVERSE_STMT(CXXOperatorCallExpr, { })
DEF_TRAVERSE_STMT(OpaqueValueExpr, { })