Author: dcoughlin Date: Sat Nov 14 21:07:17 2015 New Revision: 253157 URL: http://llvm.org/viewvc/llvm-project?rev=253157&view=rev Log: [analyzer] Refer to capture field to determine if capture is reference.
The analyzer incorrectly treats captures as references if either the original captured variable is a reference or the variable is captured by reference. This causes the analyzer to crash when capturing a reference type by copy (PR24914). Fix this by refering solely to the capture field to determine when a DeclRefExpr for a lambda capture should be treated as a reference type. https://llvm.org/bugs/show_bug.cgi?id=24914 rdar://problem/23524412 Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp cfe/trunk/test/Analysis/lambdas.cpp Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp?rev=253157&r1=253156&r2=253157&view=diff ============================================================================== --- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp Sat Nov 14 21:07:17 2015 @@ -1867,7 +1867,7 @@ void ExprEngine::VisitCommonDeclRefExpr( const auto *MD = D ? dyn_cast<CXXMethodDecl>(D) : nullptr; const auto *DeclRefEx = dyn_cast<DeclRefExpr>(Ex); SVal V; - bool CaptureByReference = false; + bool IsReference; if (AMgr.options.shouldInlineLambdas() && DeclRefEx && DeclRefEx->refersToEnclosingVariableOrCapture() && MD && MD->getParent()->isLambda()) { @@ -1882,22 +1882,22 @@ void ExprEngine::VisitCommonDeclRefExpr( // created in the lambda object. assert(VD->getType().isConstQualified()); V = state->getLValue(VD, LocCtxt); + IsReference = false; } else { Loc CXXThis = svalBuilder.getCXXThis(MD, LocCtxt->getCurrentStackFrame()); SVal CXXThisVal = state->getSVal(CXXThis); V = state->getLValue(FD, CXXThisVal); - if (FD->getType()->isReferenceType() && - !VD->getType()->isReferenceType()) - CaptureByReference = true; + IsReference = FD->getType()->isReferenceType(); } } else { V = state->getLValue(VD, LocCtxt); + IsReference = VD->getType()->isReferenceType(); } // For references, the 'lvalue' is the pointer address stored in the // reference region. - if (VD->getType()->isReferenceType() || CaptureByReference) { + if (IsReference) { if (const MemRegion *R = V.getAsRegion()) V = state->getSVal(R); else Modified: cfe/trunk/test/Analysis/lambdas.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/lambdas.cpp?rev=253157&r1=253156&r2=253157&view=diff ============================================================================== --- cfe/trunk/test/Analysis/lambdas.cpp (original) +++ cfe/trunk/test/Analysis/lambdas.cpp Sat Nov 14 21:07:17 2015 @@ -90,6 +90,17 @@ void testReturnValue() { clang_analyzer_eval(b == 8); // expected-warning{{TRUE}} } +void testAliasingBetweenParameterAndCapture() { + int i = 5; + + auto l = [&i](int &p) { + i++; + p++; + }; + l(i); + clang_analyzer_eval(i == 7); // expected-warning{{TRUE}} +} + // Nested lambdas. void testNestedLambdas() { @@ -210,6 +221,67 @@ void captureConstants() { }(); } +void captureReferenceByCopy(int &p) { + int v = 7; + p = 8; + + // p is a reference captured by copy + [&v,p]() mutable { + v = p; + p = 22; + }(); + + clang_analyzer_eval(v == 8); // expected-warning{{TRUE}} + clang_analyzer_eval(p == 8); // expected-warning{{TRUE}} +} + +void captureReferenceByReference(int &p) { + int v = 7; + p = 8; + + // p is a reference captured by reference + [&v,&p]() { + v = p; + p = 22; + }(); + + clang_analyzer_eval(v == 8); // expected-warning{{TRUE}} + clang_analyzer_eval(p == 22); // expected-warning{{TRUE}} +} + +void callMutableLambdaMultipleTimes(int &p) { + int v = 0; + p = 8; + + auto l = [&v, p]() mutable { + v = p; + p++; + }; + + l(); + + clang_analyzer_eval(v == 8); // expected-warning{{TRUE}} + clang_analyzer_eval(p == 8); // expected-warning{{TRUE}} + + l(); + + clang_analyzer_eval(v == 9); // expected-warning{{TRUE}} + clang_analyzer_eval(p == 8); // expected-warning{{TRUE}} +} + +// PR 24914 +struct StructPR24914{ + int x; +}; + +void takesConstStructArgument(const StructPR24914&); +void captureStructReference(const StructPR24914& s) { + [s]() { + takesConstStructArgument(s); + }(); +} + + // CHECK: [B2 (ENTRY)] // CHECK: Succs (1): B1 // CHECK: [B1] _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits