From: George Karpenkov Date: Tue, 20 Mar 2018 00:20:58 +0000 (+0000) Subject: [analyzer] Fix the assertion failure when static globals are used in lambda by reference X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=ed2defa004d3c64cd304796f27b34e95e6511060;p=clang [analyzer] Fix the assertion failure when static globals are used in lambda by reference Also use the opportunity to clean up the code and remove unnecessary duplication. rdar://37625895 Differential Revision: https://reviews.llvm.org/D44594 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@327926 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp index 2c3d2f0bc5..e6e5be0d13 100644 --- a/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -2462,8 +2462,8 @@ void ExprEngine::VisitCommonDeclRefExpr(const Expr *Ex, const NamedDecl *D, const Decl *D = LocCtxt->getDecl(); const auto *MD = D ? dyn_cast(D) : nullptr; const auto *DeclRefEx = dyn_cast(Ex); - SVal V; - bool IsReference; + Optional> VInfo; + if (AMgr.options.shouldInlineLambdas() && DeclRefEx && DeclRefEx->refersToEnclosingVariableOrCapture() && MD && MD->getParent()->isLambda()) { @@ -2472,25 +2472,23 @@ void ExprEngine::VisitCommonDeclRefExpr(const Expr *Ex, const NamedDecl *D, llvm::DenseMap LambdaCaptureFields; FieldDecl *LambdaThisCaptureField; CXXRec->getCaptureFields(LambdaCaptureFields, LambdaThisCaptureField); - const FieldDecl *FD = LambdaCaptureFields[VD]; - if (!FD) { - // When a constant is captured, sometimes no corresponding field is - // created in the lambda object. - assert(VD->getType().isConstQualified()); - V = state->getLValue(VD, LocCtxt); - IsReference = false; - } else { + + // Sema follows a sequence of complex rules to determine whether the + // variable should be captured. + if (const FieldDecl *FD = LambdaCaptureFields[VD]) { Loc CXXThis = svalBuilder.getCXXThis(MD, LocCtxt->getCurrentStackFrame()); SVal CXXThisVal = state->getSVal(CXXThis); - V = state->getLValue(FD, CXXThisVal); - IsReference = FD->getType()->isReferenceType(); + VInfo = std::make_pair(state->getLValue(FD, CXXThisVal), FD->getType()); } - } else { - V = state->getLValue(VD, LocCtxt); - IsReference = VD->getType()->isReferenceType(); } + if (!VInfo) + VInfo = std::make_pair(state->getLValue(VD, LocCtxt), VD->getType()); + + SVal V = VInfo->first; + bool IsReference = VInfo->second->isReferenceType(); + // For references, the 'lvalue' is the pointer address stored in the // reference region. if (IsReference) { diff --git a/test/Analysis/lambdas.cpp b/test/Analysis/lambdas.cpp index 38a2e3a84f..320ba2aabc 100644 --- a/test/Analysis/lambdas.cpp +++ b/test/Analysis/lambdas.cpp @@ -348,6 +348,23 @@ void testCapturedConstExprFloat() { lambda(); } + +static int b = 0; + +int f() { + b = 0; + auto &bm = b; + [&] { + bm++; + bm++; + }(); + if (bm != 2) { + int *y = 0; + return *y; // no-warning + } + return 0; +} + // CHECK: [B2 (ENTRY)] // CHECK: Succs (1): B1 // CHECK: [B1]