summaryrefslogtreecommitdiffstats
path: root/test/Analysis/lambdas.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'test/Analysis/lambdas.cpp')
-rw-r--r--test/Analysis/lambdas.cpp336
1 files changed, 335 insertions, 1 deletions
diff --git a/test/Analysis/lambdas.cpp b/test/Analysis/lambdas.cpp
index 33e216b..0b66e6b 100644
--- a/test/Analysis/lambdas.cpp
+++ b/test/Analysis/lambdas.cpp
@@ -1,9 +1,343 @@
-// RUN: %clang_cc1 -std=c++11 -fsyntax-only -analyze -analyzer-checker=debug.DumpCFG %s > %t 2>&1
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -analyze -analyzer-checker=core,deadcode,debug.ExprInspection -analyzer-config inline-lambdas=true -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -analyze -analyzer-checker=core,debug.DumpCFG -analyzer-config inline-lambdas=true %s > %t 2>&1
// RUN: FileCheck --input-file=%t %s
+void clang_analyzer_warnIfReached();
+void clang_analyzer_eval(int);
+
struct X { X(const X&); };
void f(X x) { (void) [x]{}; }
+
+// Lambda semantics tests.
+
+void basicCapture() {
+ int i = 5;
+ [i]() mutable {
+ // clang_analyzer_eval does nothing in inlined functions.
+ if (i != 5)
+ clang_analyzer_warnIfReached();
+ ++i;
+ }();
+ [&i] {
+ if (i != 5)
+ clang_analyzer_warnIfReached();
+ }();
+ [&i] {
+ if (i != 5)
+ clang_analyzer_warnIfReached();
+ i++;
+ }();
+ clang_analyzer_eval(i == 6); // expected-warning{{TRUE}}
+}
+
+void deferredLambdaCall() {
+ int i = 5;
+ auto l1 = [i]() mutable {
+ if (i != 5)
+ clang_analyzer_warnIfReached();
+ ++i;
+ };
+ auto l2 = [&i] {
+ if (i != 5)
+ clang_analyzer_warnIfReached();
+ };
+ auto l3 = [&i] {
+ if (i != 5)
+ clang_analyzer_warnIfReached();
+ i++;
+ };
+ l1();
+ l2();
+ l3();
+ clang_analyzer_eval(i == 6); // expected-warning{{TRUE}}
+}
+
+void multipleCaptures() {
+ int i = 5, j = 5;
+ [i, &j]() mutable {
+ if (i != 5 && j != 5)
+ clang_analyzer_warnIfReached();
+ ++i;
+ ++j;
+ }();
+ clang_analyzer_eval(i == 5); // expected-warning{{TRUE}}
+ clang_analyzer_eval(j == 6); // expected-warning{{TRUE}}
+ [=]() mutable {
+ if (i != 5 && j != 6)
+ clang_analyzer_warnIfReached();
+ ++i;
+ ++j;
+ }();
+ clang_analyzer_eval(i == 5); // expected-warning{{TRUE}}
+ clang_analyzer_eval(j == 6); // expected-warning{{TRUE}}
+ [&]() mutable {
+ if (i != 5 && j != 6)
+ clang_analyzer_warnIfReached();
+ ++i;
+ ++j;
+ }();
+ clang_analyzer_eval(i == 6); // expected-warning{{TRUE}}
+ clang_analyzer_eval(j == 7); // expected-warning{{TRUE}}
+}
+
+void testReturnValue() {
+ int i = 5;
+ auto l = [i] (int a) {
+ return i + a;
+ };
+ int b = l(3);
+ 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() {
+ int i = 5;
+ auto l = [i]() mutable {
+ [&i]() {
+ ++i;
+ }();
+ if (i != 6)
+ clang_analyzer_warnIfReached();
+ };
+ l();
+ clang_analyzer_eval(i == 5); // expected-warning{{TRUE}}
+}
+
+// Captured this.
+
+class RandomClass {
+ int i;
+
+ void captureFields() {
+ i = 5;
+ [this]() {
+ // clang_analyzer_eval does nothing in inlined functions.
+ if (i != 5)
+ clang_analyzer_warnIfReached();
+ ++i;
+ }();
+ clang_analyzer_eval(i == 6); // expected-warning{{TRUE}}
+ }
+};
+
+
+// Nested this capture.
+
+class RandomClass2 {
+ int i;
+
+ void captureFields() {
+ i = 5;
+ [this]() {
+ // clang_analyzer_eval does nothing in inlined functions.
+ if (i != 5)
+ clang_analyzer_warnIfReached();
+ ++i;
+ [this]() {
+ // clang_analyzer_eval does nothing in inlined functions.
+ if (i != 6)
+ clang_analyzer_warnIfReached();
+ ++i;
+ }();
+ }();
+ clang_analyzer_eval(i == 7); // expected-warning{{TRUE}}
+ }
+};
+
+
+// Captured function pointers.
+
+void inc(int &x) {
+ ++x;
+}
+
+void testFunctionPointerCapture() {
+ void (*func)(int &) = inc;
+ int i = 5;
+ [&i, func] {
+ func(i);
+ }();
+ clang_analyzer_eval(i == 6); // expected-warning{{TRUE}}
+}
+
+// Captured variable-length array.
+
+void testVariableLengthArrayCaptured() {
+ int n = 2;
+ int array[n];
+ array[0] = 7;
+
+ int i = [&]{
+ return array[0];
+ }();
+
+ clang_analyzer_eval(i == 7); // expected-warning{{TRUE}}
+}
+
+// Test inline defensive checks
+int getNum();
+
+void inlineDefensiveChecks() {
+ int i = getNum();
+ [=]() {
+ if (i == 0)
+ ;
+ }();
+ int p = 5/i;
+ (void)p;
+}
+
+
+template<typename T>
+void callLambda(T t) {
+ t();
+}
+
+struct DontCrash {
+ int x;
+ void f() {
+ callLambda([&](){ ++x; });
+ callLambdaFromStatic([&](){ ++x; });
+ }
+
+ template<typename T>
+ static void callLambdaFromStatic(T t) {
+ t();
+ }
+};
+
+
+// Capture constants
+
+void captureConstants() {
+ const int i = 5;
+ [=]() {
+ if (i != 5)
+ clang_analyzer_warnIfReached();
+ }();
+ [&] {
+ if (i != 5)
+ clang_analyzer_warnIfReached();
+ }();
+}
+
+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);
+ }();
+}
+
+// Lambda capture counts as use for dead-store checking.
+
+int returnsValue();
+
+void captureByCopyCausesUse() {
+ int local1 = returnsValue(); // no-warning
+ int local2 = returnsValue(); // no-warning
+ int local3 = returnsValue(); // expected-warning{{Value stored to 'local3' during its initialization is never read}}
+
+ (void)[local1, local2]() { }; // Explicit capture by copy counts as use.
+
+ int local4 = returnsValue(); // no-warning
+ int local5 = returnsValue(); // expected-warning{{Value stored to 'local5' during its initialization is never read}}
+
+ (void)[=]() {
+ (void)local4; // Implicit capture by copy counts as use
+ };
+}
+
+void captureByReference() {
+ int local1 = returnsValue(); // no-warning
+
+ auto lambda1 = [&local1]() { // Explicit capture by reference
+ local1++;
+ };
+
+ // Don't treat as a dead store because local1 was was captured by reference.
+ local1 = 7; // no-warning
+
+ lambda1();
+
+ int local2 = returnsValue(); // no-warning
+
+ auto lambda2 = [&]() {
+ local2++; // Implicit capture by reference
+ };
+
+ // Don't treat as a dead store because local2 was was captured by reference.
+ local2 = 7; // no-warning
+
+ lambda2();
+}
+
+
// CHECK: [B2 (ENTRY)]
// CHECK: Succs (1): B1
// CHECK: [B1]
OpenPOWER on IntegriCloud