diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2019-05-28 23:09:44 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2019-05-28 23:09:44 +0000 |
commit | 8465d5be63dbbd4ddb6adbab087b2a532bdc9e2b (patch) | |
tree | b1e03b7558748c66bea5dd720fd9edc303b96c57 /lib/Sema | |
parent | 2ee14504678565a83ad74c0e85f8cb58abb9ffe3 (diff) | |
download | clang-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.cpp | 2 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 108 | ||||
-rw-r--r-- | lib/Sema/SemaLambda.cpp | 5 | ||||
-rw-r--r-- | lib/Sema/SemaStmt.cpp | 3 |
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)); |