summaryrefslogtreecommitdiff
path: root/lib/Sema
diff options
context:
space:
mode:
authorRichard Smith <richard-llvm@metafoo.co.uk>2019-05-28 23:09:44 +0000
committerRichard Smith <richard-llvm@metafoo.co.uk>2019-05-28 23:09:44 +0000
commit8465d5be63dbbd4ddb6adbab087b2a532bdc9e2b (patch)
treeb1e03b7558748c66bea5dd720fd9edc303b96c57 /lib/Sema
parent2ee14504678565a83ad74c0e85f8cb58abb9ffe3 (diff)
downloadclang-8465d5be63dbbd4ddb6adbab087b2a532bdc9e2b.tar.gz
If capturing a variable fails, add a capture anyway (and mark it
invalid) so that we can avoid repeated diagnostics for the same capture. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@361891 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema')
-rw-r--r--lib/Sema/SemaDecl.cpp2
-rw-r--r--lib/Sema/SemaExpr.cpp108
-rw-r--r--lib/Sema/SemaLambda.cpp5
-rw-r--r--lib/Sema/SemaStmt.cpp3
4 files changed, 68 insertions, 50 deletions
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index a035f200fc..188e801b4c 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -12939,7 +12939,7 @@ static void RebuildLambdaScopeInfo(CXXMethodDecl *CallOperator,
/*RefersToEnclosingVariableOrCapture*/true, C.getLocation(),
/*EllipsisLoc*/C.isPackExpansion()
? C.getEllipsisLoc() : SourceLocation(),
- CaptureType, /*Expr*/ nullptr);
+ CaptureType, /*Expr*/ nullptr, /*Invalid*/false);
} else if (C.capturesThis()) {
LSI->addThisCapture(/*Nested*/ false, C.getLocation(),
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index cc3dea9ead..95be7af8b6 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -13853,10 +13853,9 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
QualType BlockTy;
// Set the captured variables on the block.
- // FIXME: Share capture structure between BlockDecl and CapturingScopeInfo!
SmallVector<BlockDecl::Capture, 4> Captures;
for (Capture &Cap : BSI->Captures) {
- if (Cap.isThisCapture())
+ if (Cap.isInvalid() || Cap.isThisCapture())
continue;
BlockDecl::Capture NewCap(Cap.getVariable(), Cap.isBlockCapture(),
Cap.isNested(), Cap.getInitExpr());
@@ -15212,31 +15211,36 @@ static bool captureInBlock(BlockScopeInfo *BSI, VarDecl *Var,
QualType &CaptureType,
QualType &DeclRefType,
const bool Nested,
- Sema &S) {
+ Sema &S, bool Invalid) {
Expr *CopyExpr = nullptr;
bool ByRef = false;
// Blocks are not allowed to capture arrays, excepting OpenCL.
// OpenCL v2.0 s1.12.5 (revision 40): arrays are captured by reference
// (decayed to pointers).
- if (!S.getLangOpts().OpenCL && CaptureType->isArrayType()) {
+ if (!Invalid && !S.getLangOpts().OpenCL && CaptureType->isArrayType()) {
if (BuildAndDiagnose) {
S.Diag(Loc, diag::err_ref_array_type);
S.Diag(Var->getLocation(), diag::note_previous_decl)
<< Var->getDeclName();
+ Invalid = true;
+ } else {
+ return false;
}
- return false;
}
// Forbid the block-capture of autoreleasing variables.
- if (CaptureType.getObjCLifetime() == Qualifiers::OCL_Autoreleasing) {
+ if (!Invalid &&
+ CaptureType.getObjCLifetime() == Qualifiers::OCL_Autoreleasing) {
if (BuildAndDiagnose) {
S.Diag(Loc, diag::err_arc_autoreleasing_capture)
<< /*block*/ 0;
S.Diag(Var->getLocation(), diag::note_previous_decl)
<< Var->getDeclName();
+ Invalid = true;
+ } else {
+ return false;
}
- return false;
}
// Warn about implicitly autoreleasing indirect parameters captured by blocks.
@@ -15259,7 +15263,7 @@ static bool captureInBlock(BlockScopeInfo *BSI, VarDecl *Var,
QualType PointeeTy = PT->getPointeeType();
- if (PointeeTy->getAs<ObjCObjectPointerType>() &&
+ if (!Invalid && PointeeTy->getAs<ObjCObjectPointerType>() &&
PointeeTy.getObjCLifetime() == Qualifiers::OCL_Autoreleasing &&
!IsObjCOwnershipAttributedType(PointeeTy)) {
if (BuildAndDiagnose) {
@@ -15323,11 +15327,10 @@ static bool captureInBlock(BlockScopeInfo *BSI, VarDecl *Var,
// Actually capture the variable.
if (BuildAndDiagnose)
- BSI->addCapture(Var, HasBlocksAttr, ByRef, Nested, Loc,
- SourceLocation(), CaptureType, CopyExpr);
-
- return true;
+ BSI->addCapture(Var, HasBlocksAttr, ByRef, Nested, Loc, SourceLocation(),
+ CaptureType, CopyExpr, Invalid);
+ return !Invalid;
}
@@ -15339,7 +15342,7 @@ static bool captureInCapturedRegion(CapturedRegionScopeInfo *RSI,
QualType &CaptureType,
QualType &DeclRefType,
const bool RefersToCapturedVariable,
- Sema &S) {
+ Sema &S, bool Invalid) {
// By default, capture variables by reference.
bool ByRef = true;
// Using an LValue reference type is consistent with Lambdas (see below).
@@ -15384,11 +15387,11 @@ static bool captureInCapturedRegion(CapturedRegionScopeInfo *RSI,
// Actually capture the variable.
if (BuildAndDiagnose)
- RSI->addCapture(Var, /*isBlock*/false, ByRef, RefersToCapturedVariable, Loc,
- SourceLocation(), CaptureType, CopyExpr);
+ RSI->addCapture(Var, /*isBlock*/ false, ByRef, RefersToCapturedVariable,
+ Loc, SourceLocation(), CaptureType, CopyExpr,
+ Invalid);
-
- return true;
+ return !Invalid;
}
/// Create a field within the lambda class for the variable
@@ -15435,8 +15438,7 @@ static bool captureInLambda(LambdaScopeInfo *LSI,
const Sema::TryCaptureKind Kind,
SourceLocation EllipsisLoc,
const bool IsTopScope,
- Sema &S) {
-
+ Sema &S, bool Invalid) {
// Determine whether we are capturing by reference or by value.
bool ByRef = false;
if (IsTopScope && Kind != Sema::TryCapture_Implicit) {
@@ -15477,31 +15479,33 @@ static bool captureInLambda(LambdaScopeInfo *LSI,
}
// Forbid the lambda copy-capture of autoreleasing variables.
- if (CaptureType.getObjCLifetime() == Qualifiers::OCL_Autoreleasing) {
+ if (!Invalid &&
+ CaptureType.getObjCLifetime() == Qualifiers::OCL_Autoreleasing) {
if (BuildAndDiagnose) {
S.Diag(Loc, diag::err_arc_autoreleasing_capture) << /*lambda*/ 1;
S.Diag(Var->getLocation(), diag::note_previous_decl)
<< Var->getDeclName();
+ Invalid = true;
+ } else {
+ return false;
}
- return false;
}
// Make sure that by-copy captures are of a complete and non-abstract type.
- if (BuildAndDiagnose) {
+ if (!Invalid && BuildAndDiagnose) {
if (!CaptureType->isDependentType() &&
S.RequireCompleteType(Loc, CaptureType,
diag::err_capture_of_incomplete_type,
Var->getDeclName()))
- return false;
-
- if (S.RequireNonAbstractType(Loc, CaptureType,
- diag::err_capture_of_abstract_type))
- return false;
+ Invalid = true;
+ else if (S.RequireNonAbstractType(Loc, CaptureType,
+ diag::err_capture_of_abstract_type))
+ Invalid = true;
}
}
// Capture this variable in the lambda.
- if (BuildAndDiagnose)
+ if (BuildAndDiagnose && !Invalid)
addAsFieldToClosureType(S, LSI, CaptureType, DeclRefType, Loc,
RefersToCapturedVariable);
@@ -15522,9 +15526,10 @@ static bool captureInLambda(LambdaScopeInfo *LSI,
// Add the capture.
if (BuildAndDiagnose)
LSI->addCapture(Var, /*IsBlock=*/false, ByRef, RefersToCapturedVariable,
- Loc, EllipsisLoc, CaptureType, /*CopyExpr=*/nullptr);
+ Loc, EllipsisLoc, CaptureType, /*CopyExpr=*/nullptr,
+ Invalid);
- return true;
+ return !Invalid;
}
bool Sema::tryCaptureVariable(
@@ -15622,11 +15627,6 @@ bool Sema::tryCaptureVariable(
}
return true;
}
- // Certain capturing entities (lambdas, blocks etc.) are not allowed to capture
- // certain types of variables (unnamed, variably modified types etc.)
- // so check for eligibility.
- if (!isVariableCapturable(CSI, Var, ExprLoc, BuildAndDiagnose, *this))
- return true;
// Try to capture variable-length arrays types.
if (Var->getType()->isVariablyModifiedType()) {
@@ -15697,33 +15697,45 @@ bool Sema::tryCaptureVariable(
// requirements, and adding captures if requested.
// If the variable had already been captured previously, we start capturing
// at the lambda nested within that one.
+ bool Invalid = false;
for (unsigned I = ++FunctionScopesIndex, N = MaxFunctionScopesIndex + 1; I != N;
++I) {
CapturingScopeInfo *CSI = cast<CapturingScopeInfo>(FunctionScopes[I]);
+ // Certain capturing entities (lambdas, blocks etc.) are not allowed to capture
+ // certain types of variables (unnamed, variably modified types etc.)
+ // so check for eligibility.
+ if (!Invalid)
+ Invalid =
+ !isVariableCapturable(CSI, Var, ExprLoc, BuildAndDiagnose, *this);
+
+ // After encountering an error, if we're actually supposed to capture, keep
+ // capturing in nested contexts to suppress any follow-on diagnostics.
+ if (Invalid && !BuildAndDiagnose)
+ return true;
+
if (BlockScopeInfo *BSI = dyn_cast<BlockScopeInfo>(CSI)) {
- if (!captureInBlock(BSI, Var, ExprLoc,
- BuildAndDiagnose, CaptureType,
- DeclRefType, Nested, *this))
- return true;
+ Invalid = !captureInBlock(BSI, Var, ExprLoc, BuildAndDiagnose, CaptureType,
+ DeclRefType, Nested, *this, Invalid);
Nested = true;
} else if (CapturedRegionScopeInfo *RSI = dyn_cast<CapturedRegionScopeInfo>(CSI)) {
- if (!captureInCapturedRegion(RSI, Var, ExprLoc,
- BuildAndDiagnose, CaptureType,
- DeclRefType, Nested, *this))
- return true;
+ Invalid = !captureInCapturedRegion(RSI, Var, ExprLoc, BuildAndDiagnose,
+ CaptureType, DeclRefType, Nested,
+ *this, Invalid);
Nested = true;
} else {
LambdaScopeInfo *LSI = cast<LambdaScopeInfo>(CSI);
- if (!captureInLambda(LSI, Var, ExprLoc,
- BuildAndDiagnose, CaptureType,
+ Invalid =
+ !captureInLambda(LSI, Var, ExprLoc, BuildAndDiagnose, CaptureType,
DeclRefType, Nested, Kind, EllipsisLoc,
- /*IsTopScope*/I == N - 1, *this))
- return true;
+ /*IsTopScope*/ I == N - 1, *this, Invalid);
Nested = true;
}
+
+ if (Invalid && !BuildAndDiagnose)
+ return true;
}
- return false;
+ return Invalid;
}
bool Sema::tryCaptureVariable(VarDecl *Var, SourceLocation Loc,
diff --git a/lib/Sema/SemaLambda.cpp b/lib/Sema/SemaLambda.cpp
index b2055dd650..f6c9dee2a0 100644
--- a/lib/Sema/SemaLambda.cpp
+++ b/lib/Sema/SemaLambda.cpp
@@ -854,7 +854,7 @@ FieldDecl *Sema::buildInitCaptureField(LambdaScopeInfo *LSI, VarDecl *Var) {
LSI->addCapture(Var, /*isBlock*/false, Var->getType()->isReferenceType(),
/*isNested*/false, Var->getLocation(), SourceLocation(),
- Var->getType(), Var->getInit());
+ Var->getType(), Var->getInit(), /*Invalid*/false);
return Field;
}
@@ -1586,6 +1586,9 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc,
for (unsigned I = 0, N = LSI->Captures.size(); I != N; ++I, ++CurField) {
const Capture &From = LSI->Captures[I];
+ if (From.isInvalid())
+ return ExprError();
+
assert(!From.isBlockCapture() && "Cannot capture __block variables");
bool IsImplicit = I >= LSI->NumExplicitCaptures;
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp
index c7fb565451..51a72c618b 100644
--- a/lib/Sema/SemaStmt.cpp
+++ b/lib/Sema/SemaStmt.cpp
@@ -4228,6 +4228,9 @@ buildCapturedStmtCaptureList(SmallVectorImpl<CapturedStmt::Capture> &Captures,
SmallVectorImpl<Expr *> &CaptureInits,
ArrayRef<sema::Capture> Candidates) {
for (const sema::Capture &Cap : Candidates) {
+ if (Cap.isInvalid())
+ continue;
+
if (Cap.isThisCapture()) {
Captures.push_back(CapturedStmt::Capture(Cap.getLocation(),
CapturedStmt::VCK_This));