Home | History | Annotate | Download | only in Analysis
      1 // RUN: %clang_cc1 -std=c++11 -fsyntax-only -analyze -analyzer-checker=core,deadcode,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 void testAliasingBetweenParameterAndCapture() {
     94   int i = 5;
     95 
     96   auto l = [&i](int &p) {
     97     i++;
     98     p++;
     99   };
    100   l(i);
    101   clang_analyzer_eval(i == 7); // expected-warning{{TRUE}}
    102 }
    103 
    104 // Nested lambdas.
    105 
    106 void testNestedLambdas() {
    107   int i = 5;
    108   auto l = [i]() mutable {
    109     [&i]() {
    110       ++i;
    111     }();
    112     if (i != 6)
    113       clang_analyzer_warnIfReached();
    114   };
    115   l();
    116   clang_analyzer_eval(i == 5); // expected-warning{{TRUE}}
    117 }
    118 
    119 // Captured this.
    120 
    121 class RandomClass {
    122   int i;
    123 
    124   void captureFields() {
    125     i = 5;
    126     [this]() {
    127       // clang_analyzer_eval does nothing in inlined functions.
    128       if (i != 5)
    129         clang_analyzer_warnIfReached();
    130       ++i;
    131     }();
    132     clang_analyzer_eval(i == 6); // expected-warning{{TRUE}}
    133   }
    134 };
    135 
    136 
    137 // Nested this capture.
    138 
    139 class RandomClass2 {
    140   int i;
    141 
    142   void captureFields() {
    143     i = 5;
    144     [this]() {
    145       // clang_analyzer_eval does nothing in inlined functions.
    146       if (i != 5)
    147         clang_analyzer_warnIfReached();
    148       ++i;
    149       [this]() {
    150         // clang_analyzer_eval does nothing in inlined functions.
    151         if (i != 6)
    152           clang_analyzer_warnIfReached();
    153         ++i;
    154       }();
    155     }();
    156     clang_analyzer_eval(i == 7); // expected-warning{{TRUE}}
    157   }
    158 };
    159 
    160 
    161 // Captured function pointers.
    162 
    163 void inc(int &x) {
    164   ++x;
    165 }
    166 
    167 void testFunctionPointerCapture() {
    168   void (*func)(int &) = inc;
    169   int i = 5;
    170   [&i, func] {
    171     func(i);
    172   }();
    173   clang_analyzer_eval(i == 6); // expected-warning{{TRUE}}
    174 }
    175 
    176 // Captured variable-length array.
    177 
    178 void testVariableLengthArrayCaptured() {
    179   int n = 2;
    180   int array[n];
    181   array[0] = 7;
    182 
    183   int i = [&]{
    184     return array[0];
    185   }();
    186 
    187   clang_analyzer_eval(i == 7); // expected-warning{{TRUE}}
    188 }
    189 
    190 // Test inline defensive checks
    191 int getNum();
    192 
    193 void inlineDefensiveChecks() {
    194   int i = getNum();
    195   [=]() {
    196     if (i == 0)
    197       ;
    198   }();
    199   int p = 5/i;
    200   (void)p;
    201 }
    202 
    203 
    204 template<typename T>
    205 void callLambda(T t) {
    206   t();
    207 }
    208 
    209 struct DontCrash {
    210   int x;
    211   void f() {
    212     callLambda([&](){ ++x; });
    213     callLambdaFromStatic([&](){ ++x; });
    214   }
    215 
    216   template<typename T>
    217   static void callLambdaFromStatic(T t) {
    218     t();
    219   }
    220 };
    221 
    222 
    223 // Capture constants
    224 
    225 void captureConstants() {
    226   const int i = 5;
    227   [=]() {
    228     if (i != 5)
    229       clang_analyzer_warnIfReached();
    230   }();
    231   [&] {
    232     if (i != 5)
    233       clang_analyzer_warnIfReached();
    234   }();
    235 }
    236 
    237 void captureReferenceByCopy(int &p) {
    238   int v = 7;
    239   p = 8;
    240 
    241   // p is a reference captured by copy
    242   [&v,p]() mutable {
    243     v = p;
    244     p = 22;
    245   }();
    246 
    247   clang_analyzer_eval(v == 8); // expected-warning{{TRUE}}
    248   clang_analyzer_eval(p == 8); // expected-warning{{TRUE}}
    249 }
    250 
    251 void captureReferenceByReference(int &p) {
    252   int v = 7;
    253   p = 8;
    254 
    255   // p is a reference captured by reference
    256   [&v,&p]() {
    257     v = p;
    258     p = 22;
    259   }();
    260 
    261   clang_analyzer_eval(v == 8); // expected-warning{{TRUE}}
    262   clang_analyzer_eval(p == 22); // expected-warning{{TRUE}}
    263 }
    264 
    265 void callMutableLambdaMultipleTimes(int &p) {
    266   int v = 0;
    267   p = 8;
    268 
    269   auto l = [&v, p]() mutable {
    270     v = p;
    271     p++;
    272   };
    273 
    274   l();
    275 
    276   clang_analyzer_eval(v == 8); // expected-warning{{TRUE}}
    277   clang_analyzer_eval(p == 8); // expected-warning{{TRUE}}
    278 
    279   l();
    280 
    281   clang_analyzer_eval(v == 9); // expected-warning{{TRUE}}
    282   clang_analyzer_eval(p == 8); // expected-warning{{TRUE}}
    283 }
    284 
    285 // PR 24914
    286 struct StructPR24914{
    287   int x;
    288 };
    289 
    290 void takesConstStructArgument(const StructPR24914&);
    291 void captureStructReference(const StructPR24914& s) {
    292   [s]() {
    293     takesConstStructArgument(s);
    294   }();
    295 }
    296 
    297 // Lambda capture counts as use for dead-store checking.
    298 
    299 int returnsValue();
    300 
    301 void captureByCopyCausesUse() {
    302   int local1 = returnsValue(); // no-warning
    303   int local2 = returnsValue(); // no-warning
    304   int local3 = returnsValue(); // expected-warning{{Value stored to 'local3' during its initialization is never read}}
    305 
    306   (void)[local1, local2]() { }; // Explicit capture by copy counts as use.
    307 
    308   int local4 = returnsValue(); // no-warning
    309   int local5 = returnsValue(); // expected-warning{{Value stored to 'local5' during its initialization is never read}}
    310 
    311   (void)[=]() {
    312     (void)local4; // Implicit capture by copy counts as use
    313   };
    314 }
    315 
    316 void captureByReference() {
    317   int local1 = returnsValue(); // no-warning
    318 
    319   auto lambda1 = [&local1]() { // Explicit capture by reference
    320     local1++;
    321   };
    322 
    323   // Don't treat as a dead store because local1 was was captured by reference.
    324   local1 = 7; // no-warning
    325 
    326   lambda1();
    327 
    328   int local2 = returnsValue(); // no-warning
    329 
    330   auto lambda2 = [&]() {
    331     local2++; // Implicit capture by reference
    332   };
    333 
    334   // Don't treat as a dead store because local2 was was captured by reference.
    335   local2 = 7; // no-warning
    336 
    337   lambda2();
    338 }
    339 
    340 
    341 // CHECK: [B2 (ENTRY)]
    342 // CHECK:   Succs (1): B1
    343 // CHECK: [B1]
    344 // CHECK:   1: x
    345 // CHECK:   2: [B1.1] (ImplicitCastExpr, NoOp, const struct X)
    346 // CHECK:   3: [B1.2] (CXXConstructExpr, struct X)
    347 // CHECK:   4: [x]     {
    348 // CHECK:    }
    349 // CHECK:   5: (void)[B1.4] (CStyleCastExpr, ToVoid, void)
    350 // CHECK:   Preds (1): B2
    351 // CHECK:   Succs (1): B0
    352 // CHECK: [B0 (EXIT)]
    353 // CHECK:   Preds (1): B1
    354 
    355