aboutsummaryrefslogtreecommitdiff
path: root/lib/Sema
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Sema')
-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
6 files changed, 199 insertions, 7 deletions
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);
+}