1 // RUN: %clang_cc1 -std=c++11 -fsyntax-only -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-config inline-lambdas=true -verify %s 2 // RUN: %clang_cc1 -std=c++11 -fsyntax-only -analyze -analyzer-checker=core,debug.DumpCFG -analyzer-config inline-lambdas=true %s > %t 2>&1 3 // RUN: FileCheck --input-file=%t %s 4 5 void clang_analyzer_warnIfReached(); 6 void clang_analyzer_eval(int); 7 8 struct X { X(const X&); }; 9 void f(X x) { (void) [x]{}; } 10 11 12 // Lambda semantics tests. 13 14 void basicCapture() { 15 int i = 5; 16 [i]() mutable { 17 // clang_analyzer_eval does nothing in inlined functions. 18 if (i != 5) 19 clang_analyzer_warnIfReached(); 20 ++i; 21 }(); 22 [&i] { 23 if (i != 5) 24 clang_analyzer_warnIfReached(); 25 }(); 26 [&i] { 27 if (i != 5) 28 clang_analyzer_warnIfReached(); 29 i++; 30 }(); 31 clang_analyzer_eval(i == 6); // expected-warning{{TRUE}} 32 } 33 34 void deferredLambdaCall() { 35 int i = 5; 36 auto l1 = [i]() mutable { 37 if (i != 5) 38 clang_analyzer_warnIfReached(); 39 ++i; 40 }; 41 auto l2 = [&i] { 42 if (i != 5) 43 clang_analyzer_warnIfReached(); 44 }; 45 auto l3 = [&i] { 46 if (i != 5) 47 clang_analyzer_warnIfReached(); 48 i++; 49 }; 50 l1(); 51 l2(); 52 l3(); 53 clang_analyzer_eval(i == 6); // expected-warning{{TRUE}} 54 } 55 56 void multipleCaptures() { 57 int i = 5, j = 5; 58 [i, &j]() mutable { 59 if (i != 5 && j != 5) 60 clang_analyzer_warnIfReached(); 61 ++i; 62 ++j; 63 }(); 64 clang_analyzer_eval(i == 5); // expected-warning{{TRUE}} 65 clang_analyzer_eval(j == 6); // expected-warning{{TRUE}} 66 [=]() mutable { 67 if (i != 5 && j != 6) 68 clang_analyzer_warnIfReached(); 69 ++i; 70 ++j; 71 }(); 72 clang_analyzer_eval(i == 5); // expected-warning{{TRUE}} 73 clang_analyzer_eval(j == 6); // expected-warning{{TRUE}} 74 [&]() mutable { 75 if (i != 5 && j != 6) 76 clang_analyzer_warnIfReached(); 77 ++i; 78 ++j; 79 }(); 80 clang_analyzer_eval(i == 6); // expected-warning{{TRUE}} 81 clang_analyzer_eval(j == 7); // expected-warning{{TRUE}} 82 } 83 84 void testReturnValue() { 85 int i = 5; 86 auto l = [i] (int a) { 87 return i + a; 88 }; 89 int b = l(3); 90 clang_analyzer_eval(b == 8); // expected-warning{{TRUE}} 91 } 92 93 // Nested lambdas. 94 95 void testNestedLambdas() { 96 int i = 5; 97 auto l = [i]() mutable { 98 [&i]() { 99 ++i; 100 }(); 101 if (i != 6) 102 clang_analyzer_warnIfReached(); 103 }; 104 l(); 105 clang_analyzer_eval(i == 5); // expected-warning{{TRUE}} 106 } 107 108 // Captured this. 109 110 class RandomClass { 111 int i; 112 113 void captureFields() { 114 i = 5; 115 [this]() { 116 // clang_analyzer_eval does nothing in inlined functions. 117 if (i != 5) 118 clang_analyzer_warnIfReached(); 119 ++i; 120 }(); 121 clang_analyzer_eval(i == 6); // expected-warning{{TRUE}} 122 } 123 }; 124 125 126 // Nested this capture. 127 128 class RandomClass2 { 129 int i; 130 131 void captureFields() { 132 i = 5; 133 [this]() { 134 // clang_analyzer_eval does nothing in inlined functions. 135 if (i != 5) 136 clang_analyzer_warnIfReached(); 137 ++i; 138 [this]() { 139 // clang_analyzer_eval does nothing in inlined functions. 140 if (i != 6) 141 clang_analyzer_warnIfReached(); 142 ++i; 143 }(); 144 }(); 145 clang_analyzer_eval(i == 7); // expected-warning{{TRUE}} 146 } 147 }; 148 149 150 // Captured function pointers. 151 152 void inc(int &x) { 153 ++x; 154 } 155 156 void testFunctionPointerCapture() { 157 void (*func)(int &) = inc; 158 int i = 5; 159 [&i, func] { 160 func(i); 161 }(); 162 clang_analyzer_eval(i == 6); // expected-warning{{TRUE}} 163 } 164 165 166 // Test inline defensive checks 167 int getNum(); 168 169 void inlineDefensiveChecks() { 170 int i = getNum(); 171 [=]() { 172 if (i == 0) 173 ; 174 }(); 175 int p = 5/i; 176 (void)p; 177 } 178 179 // CHECK: [B2 (ENTRY)] 180 // CHECK: Succs (1): B1 181 // CHECK: [B1] 182 // CHECK: 1: x 183 // CHECK: 2: [B1.1] (ImplicitCastExpr, NoOp, const struct X) 184 // CHECK: 3: [B1.2] (CXXConstructExpr, struct X) 185 // CHECK: 4: [x] { 186 // CHECK: } 187 // CHECK: 5: (void)[B1.4] (CStyleCastExpr, ToVoid, void) 188 // CHECK: Preds (1): B2 189 // CHECK: Succs (1): B0 190 // CHECK: [B0 (EXIT)] 191 // CHECK: Preds (1): B1 192 193